static XConfigScreenPtr clone_screen(XConfigScreenPtr screen0, int idx) { XConfigScreenPtr screen = nvalloc(sizeof(XConfigScreenRec)); screen->identifier = nvasprintf("%s (%d)", screen0->identifier, idx); screen->device = clone_device(screen0->device, idx); screen->device_name = nvstrdup(screen->device->identifier); screen->monitor = screen0->monitor; screen->monitor_name = nvstrdup(screen0->monitor_name); screen->defaultdepth = screen0->defaultdepth; screen->displays = clone_display_list(screen0->displays); screen->options = xconfigOptionListDup(screen0->options); if (screen0->comment) screen->comment = nvstrdup(screen0->comment); /* insert the new screen after the original screen */ screen->next = screen0->next; screen0->next = screen; return screen; } /* clone_screen() */
static void create_adjacencies(Options *op, XConfigPtr config, XConfigLayoutPtr layout) { XConfigAdjacencyPtr adj, prev_adj; XConfigScreenPtr screen; int i; i = 0; prev_adj = NULL; for (screen = config->screens; screen; screen = screen->next) { adj = nvalloc(sizeof(XConfigAdjacencyRec)); adj->scrnum = i; adj->screen_name = nvstrdup(screen->identifier); adj->screen = screen; if (prev_adj) { prev_adj->next = adj; } else { layout->adjacencies = adj; } prev_adj = adj; i++; } xconfigGenerateAssignScreenAdjacencies(layout); } /* create_adjacencies() */
void *nvrealloc(void *ptr, size_t size) { void *m; if (ptr == NULL) return nvalloc(size); m = realloc(ptr, size); if (!m) { fprintf(stderr, "%s: memory re-allocation failure (%s)! \n", PROGRAM_NAME, strerror(errno)); exit(1); } return m; } /* nvrealloc() */
/* * Read from the given FILE stream until a newline, EOF, or nul * terminator is encountered, writing data into a growable buffer. * The eof parameter is set to TRUE when EOF is encountered. In all * cases, the returned string is null-terminated. * * XXX this function will be rather slow because it uses fgetc() to * pull each character off the stream one at a time; this is done so * that each character can be examined as it's read so that we can * appropriately deal with EOFs and newlines. A better implementation * would use fgets(), but that would still require us to parse each * read line, checking for newlines or guessing if we hit an EOF. */ char *fget_next_line(FILE *fp, int *eof) { char *buf = NULL, *tmpbuf; char *c = NULL; int len = 0, buflen = 0; int ret; const int __fget_next_line_len = 32; if (eof) { *eof = FALSE; } while (1) { if (buflen == len) { /* buffer isn't big enough -- grow it */ buflen += __fget_next_line_len; tmpbuf = nvalloc(buflen); if (buf) { memcpy(tmpbuf, buf, len); nvfree(buf); } buf = tmpbuf; c = buf + len; } ret = fgetc(fp); if ((ret == EOF) && (eof)) { *eof = TRUE; } if ((ret == EOF) || (ret == '\n') || (ret == '\0')) { *c = '\0'; return buf; } *c = (char) ret; len++; c++; } /* while (1) */ return NULL; /* should never get here */ }
static XConfigDisplayPtr clone_display_list(XConfigDisplayPtr display0) { XConfigDisplayPtr d = NULL, prev = NULL, head = NULL; while (display0) { d = nvalloc(sizeof(XConfigDisplayRec)); memcpy(d, display0, sizeof(XConfigDisplayRec)); if (display0->visual) d->visual = nvstrdup(display0->visual); if (display0->comment) d->comment = nvstrdup(display0->comment); d->options = xconfigOptionListDup(display0->options); d->next = NULL; if (prev) prev->next = d; if (!head) head = d; prev = d; display0 = display0->next; } return head; } /* clone_display_list() */
void ctk_help_data_list_prepend(GList **list, const gchar *label, const gchar *help_text, const gchar *extended_help_text) { CtkHelpDataItem *item; if (!label || !help_text) { return; } item = nvalloc(sizeof(CtkHelpDataItem)); item->label = nvstrdup(label); item->help_text = nvstrdup(help_text); item->extended_help_text = extended_help_text ? nvstrdup(extended_help_text) : NULL; *list = g_list_prepend(*list, item); }
char *nvstrcat(const char *str, ...) { const char *s; char *result; size_t len; va_list ap; /* walk the varargs to compute the length of the result string */ va_start(ap, str); for (s = str, len = 1; s; s = va_arg(ap, char *)) { len += strlen(s); } va_end(ap); /* allocate the result string */ result = nvalloc(len); if (!result) return result; result[0] = '\0'; /* concatenate the input strings, writing into the result string */ va_start(ap, str); for (s = str; s; s = va_arg(ap, char *)) { strcat(result, s); } va_end(ap); return result; } /* nvstrcat() */
static XConfigDevicePtr clone_device(XConfigDevicePtr device0, int idx) { XConfigDevicePtr device; device = nvalloc(sizeof(XConfigDeviceRec)); device->identifier = nvasprintf("%s (%d)", device0->identifier, idx); if (device0->vendor) device->vendor = nvstrdup(device0->vendor); if (device0->board) device->board = nvstrdup(device0->board); if (device0->chipset) device->chipset = nvstrdup(device0->chipset); if (device0->busid) device->busid = nvstrdup(device0->busid); if (device0->card) device->card = nvstrdup(device0->card); if (device0->driver) device->driver = nvstrdup(device0->driver); if (device0->ramdac) device->ramdac = nvstrdup(device0->ramdac); if (device0->comment) device->comment = nvstrdup(device0->comment); /* these are needed for multiple X screens on one GPU */ device->screen = idx; device0->screen = 0; device->chipid = -1; device->chiprev = -1; device->irq = -1; device->options = xconfigOptionListDup(device0->options); /* insert the new device after the original device */ device->next = device0->next; device0->next = device; return device; } /* clone_device() */
/* * 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; } }
static int enable_separate_x_screens(Options *op, XConfigPtr config, XConfigLayoutPtr layout) { XConfigScreenPtr screen, *screenlist = NULL; XConfigAdjacencyPtr adj; int* screens_to_clone = NULL; int i, nscreens = 0; int have_busids; /* step 1: build the list of screens that are candidate to be cloned */ if (op->screen) { screen = xconfigFindScreen(op->screen, config->screens); if (!screen) { nv_error_msg("Unable to find screen '%s'.", op->screen); return FALSE; } screenlist = nvalloc(sizeof(XConfigScreenPtr)); screenlist[0] = screen; nscreens = 1; } else { for (adj = layout->adjacencies; adj; adj = adj->next) { nscreens++; screenlist = realloc(screenlist, sizeof(XConfigScreenPtr) * nscreens); screenlist[nscreens-1] = adj->screen; } } if (!nscreens) return FALSE; /* step 2: do all screens in the list have a bus ID? */ have_busids = TRUE; for (i = 0; i < nscreens; i++) { if (screenlist[i] && screenlist[i]->device && screenlist[i]->device->busid) { // this screen has a busid } else { have_busids = FALSE; break; } } /* * if not everyone has a bus id, then let's assign bus ids to all * the screens; XXX what if _some_ already have busids? Too bad, * we're going to reassign all of them. */ if (!have_busids) { DevicesPtr pDevices; pDevices = find_devices(op); if (!pDevices) { nv_error_msg("Unable to determine number or location of " "GPUs in system; cannot " "honor '--separate-x-screens' option."); return FALSE; } for (i = 0; i < nscreens; i++) { if (i >= pDevices->nDevices) { /* * we have more screens than GPUs, this screen is no * longer a candidate */ screenlist[i] = NULL; continue; } screenlist[i]->device->busid = nvalloc(32); xconfigFormatPciBusString(screenlist[i]->device->busid, 32, pDevices->devices[i].dev.domain, pDevices->devices[i].dev.bus, pDevices->devices[i].dev.slot, 0); screenlist[i]->device->board = nvstrdup(pDevices->devices[i].name); } free_devices(pDevices); } /* step 3 */ clean_screen_list(screenlist, config, nscreens); /* step 4 */ screens_to_clone = get_screens_to_clone(op, screenlist, nscreens); /* step 5: clone each eligible screen */ for (i = 0; i < nscreens; i++) { if (!screenlist[i]) continue; while (--screens_to_clone[i] > 0) { clone_screen(screenlist[i], screens_to_clone[i]); } } nvfree(screens_to_clone); /* 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); return TRUE; } /* enable_separate_x_screens() */
/* * 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; }
static Package *parse_manifest (Options *op) { char *buf, *c, *tmpstr; int line; int fd, ret, len = 0; struct stat stat_buf; Package *p; char *manifest = MAP_FAILED, *ptr; int opengl_files_packaged = FALSE; p = (Package *) nvalloc(sizeof (Package)); /* open the manifest file */ if ((fd = open(".manifest", O_RDONLY)) == -1) { ui_error(op, "No package found for installation. Please run " "this utility with the '--help' option for usage " "information."); goto fail; } if (fstat(fd, &stat_buf) == -1) goto cannot_open; len = stat_buf.st_size; manifest = mmap(0, len, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0); if (manifest == MAP_FAILED) goto cannot_open; /* the first line is the description */ line = 1; p->description = get_next_line(manifest, &ptr, manifest, len); if (!p->description) goto invalid_manifest_file; /* the second line is the version */ line++; p->version = get_next_line(ptr, &ptr, manifest, len); if (!p->version) goto invalid_manifest_file; /* Ignore the third line */ line++; nvfree(get_next_line(ptr, &ptr, manifest, len)); /* the fourth line is the list of kernel modules. */ line++; tmpstr = get_next_line(ptr, &ptr, manifest, len); if (parse_kernel_modules_list(p, tmpstr) == 0) { goto invalid_manifest_file; } nvfree(tmpstr); /* * set the default value of excluded_kernel_modules to an empty, heap * allocated string so that it can be freed and won't prematurely end * an nvstrcat()ed string when unset. */ p->excluded_kernel_modules = nvstrdup(""); /* * ignore the fifth and sixth lines */ line++; nvfree(get_next_line(ptr, &ptr, manifest, len)); line++; nvfree(get_next_line(ptr, &ptr, manifest, len)); /* the seventh line is the kernel module build directory */ line++; p->kernel_module_build_directory = get_next_line(ptr, &ptr, manifest, len); if (!p->kernel_module_build_directory) goto invalid_manifest_file; remove_trailing_slashes(p->kernel_module_build_directory); /* * the eigth line is the directory containing precompiled kernel * interfaces */ line++; p->precompiled_kernel_interface_directory = get_next_line(ptr, &ptr, manifest, len); if (!p->precompiled_kernel_interface_directory) goto invalid_manifest_file; remove_trailing_slashes(p->precompiled_kernel_interface_directory); /* the rest of the file is file entries */ line++; for (; (buf = get_next_line(ptr, &ptr, manifest, len)); line++) { char *flag = NULL; PackageEntry entry; int entry_success = FALSE; if (buf[0] == '\0') { free(buf); break; } /* initialize the new entry */ memset(&entry, 0, sizeof(PackageEntry)); /* read the file name and permissions */ c = buf; entry.file = read_next_word(buf, &c); if (!entry.file) goto entry_done; tmpstr = read_next_word(c, &c); if (!tmpstr) goto entry_done; /* translate the mode string into an octal mode */ ret = mode_string_to_mode(op, tmpstr, &entry.mode); free(tmpstr); if (!ret) goto entry_done; /* every file has a type field */ entry.type = FILE_TYPE_NONE; flag = read_next_word(c, &c); if (!flag) goto entry_done; entry.type = parse_manifest_file_type(flag, &entry.caps); if (entry.type == FILE_TYPE_NONE) { goto entry_done; } /* Track whether certain file types were packaged */ switch (entry.type) { case FILE_TYPE_XMODULE_SHARED_LIB: op->x_files_packaged = TRUE; break; default: break; } /* set opengl_files_packaged if any OpenGL files were packaged */ if (entry.caps.is_opengl) { opengl_files_packaged = TRUE; } /* some libs/symlinks have an arch field */ entry.compat_arch = FILE_COMPAT_ARCH_NONE; if (entry.caps.has_arch) { nvfree(flag); flag = read_next_word(c, &c); if (!flag) goto entry_done; if (strcmp(flag, "COMPAT32") == 0) entry.compat_arch = FILE_COMPAT_ARCH_COMPAT32; else if (strcmp(flag, "NATIVE") == 0) entry.compat_arch = FILE_COMPAT_ARCH_NATIVE; else { goto entry_done; } } /* if compat32 files are packaged, set compat32_files_packaged */ if (entry.compat_arch == FILE_COMPAT_ARCH_COMPAT32) { op->compat32_files_packaged = TRUE; } /* some libs/symlinks have a class field */ entry.tls_class = FILE_TLS_CLASS_NONE; if (entry.caps.has_tls_class) { nvfree(flag); flag = read_next_word(c, &c); if (!flag) goto entry_done; if (strcmp(flag, "CLASSIC") == 0) entry.tls_class = FILE_TLS_CLASS_CLASSIC; else if (strcmp(flag, "NEW") == 0) entry.tls_class = FILE_TLS_CLASS_NEW; else { goto entry_done; } } /* some file types have a path field, or inherit their paths */ if (entry.caps.has_path) { entry.path = read_next_word(c, &c); if (!entry.path) goto invalid_manifest_file; } else if (entry.caps.inherit_path) { int i; char *path, *depth, *slash; const char * const depth_marker = "INHERIT_PATH_DEPTH:"; depth = read_next_word(c, &c); if (!depth || strncmp(depth, depth_marker, strlen(depth_marker)) != 0) { goto invalid_manifest_file; } entry.inherit_path_depth = atoi(depth + strlen(depth_marker)); nvfree(depth); /* Remove the file component from the packaged filename */ path = entry.path = nvstrdup(entry.file); slash = strrchr(path, '/'); if (slash == NULL) { goto invalid_manifest_file; } slash[1] = '\0'; /* Strip leading directory components from the path */ for (i = 0; i < entry.inherit_path_depth; i++) { slash = strchr(entry.path, '/'); if (slash == NULL) { goto invalid_manifest_file; } entry.path = slash + 1; } entry.path = nvstrdup(entry.path); nvfree(path); } else { entry.path = NULL; } /* symlinks have a target */ if (entry.caps.is_symlink) { entry.target = read_next_word(c, &c); if (!entry.target) goto invalid_manifest_file; } else { entry.target = NULL; } /* * as a convenience for later, set the 'name' pointer to * the basename contained in 'file' (ie the portion of * 'file' without any leading directory components */ entry.name = strrchr(entry.file, '/'); if (entry.name) entry.name++; if (!entry.name) entry.name = entry.file; add_package_entry(p, entry.file, entry.path, entry.name, entry.target, entry.dst, entry.type, entry.tls_class, entry.compat_arch, entry.mode); entry_success = TRUE; entry_done: /* clean up */ nvfree(buf); nvfree(flag); if (!entry_success) { goto invalid_manifest_file; } } /* If no OpenGL files were packaged, we can't install them. Set the * no_opengl_files flag so that everything we skip when explicitly * excluding OpenGL is also skipped when OpenGL is not packaged. */ if (!opengl_files_packaged) { op->no_opengl_files = TRUE; } munmap(manifest, len); if (fd != -1) close(fd); return p; cannot_open: ui_error(op, "Failure opening package's .manifest file (%s).", strerror(errno)); goto fail; invalid_manifest_file: ui_error(op, "Invalid .manifest file; error on line %d.", line); goto fail; fail: free_package(p); if (manifest != MAP_FAILED) munmap(manifest, len); if (fd != -1) close(fd); return NULL; } /* parse_manifest() */
NvCtrlAttributeHandle *NvCtrlAttributeInit(Display *dpy, int target_type, int target_id, unsigned int subsystems) { NvCtrlAttributePrivateHandle *h = NULL; h = nvalloc(sizeof (NvCtrlAttributePrivateHandle)); /* initialize the display and screen to the parameter values */ h->dpy = dpy; h->target_type = target_type; h->target_id = target_id; /* initialize the NV-CONTROL attributes; give up if this fails */ if (subsystems & NV_CTRL_ATTRIBUTES_NV_CONTROL_SUBSYSTEM) { h->nv = NvCtrlInitNvControlAttributes(h); if (!h->nv) goto failed; } /* * initialize X Screen specific attributes for X Screen * target types. */ if (target_type == NV_CTRL_TARGET_TYPE_X_SCREEN) { /* * initialize the XF86VidMode attributes; it is OK if this * fails */ if (subsystems & NV_CTRL_ATTRIBUTES_XF86VIDMODE_SUBSYSTEM) { h->vm = NvCtrlInitVidModeAttributes(h); } /* * initialize the XVideo extension and attributes; it is OK if * this fails */ if (subsystems & NV_CTRL_ATTRIBUTES_XVIDEO_SUBSYSTEM) { h->xv = NvCtrlInitXvAttributes(h); } /* * initialize the GLX extension and attributes; it is OK if * this fails */ if (subsystems & NV_CTRL_ATTRIBUTES_GLX_SUBSYSTEM) { h->glx = NvCtrlInitGlxAttributes(h); } } /* X Screen target type attribute subsystems */ /* * initialize the XRandR extension and attributes; this does not * require an X screen and it is OK if this fails */ if (subsystems & NV_CTRL_ATTRIBUTES_XRANDR_SUBSYSTEM) { h->xrandr = NvCtrlInitXrandrAttributes(h); } return (NvCtrlAttributeHandle *) h; failed: if (h) free (h); return NULL; } /* NvCtrlAttributeInit() */
static int parse_config_property(const char *file, const char *line, ConfigProperties *conf) { char *no_spaces, *s; char *locale; ConfigPropertiesTableEntry *t; char *timer, *token; TimerConfigProperty *c = NULL; int interval; int ret = NV_FALSE; unsigned int flag; no_spaces = remove_spaces(line); if (!no_spaces) goto done; s = strchr(no_spaces, '='); if (!s) goto done; *s = '\0'; if (nv_strcasecmp(no_spaces, "RcFileLocale")) { locale = ++s; if (setlocale(LC_NUMERIC, locale) == NULL) { nv_warning_msg("Error parsing configuration file '%s': could " "not set the specified locale '%s'.", file, locale); } } else if (nv_strcasecmp(no_spaces, "Timer")) { timer = ++s; token = strtok(timer, ","); if (!token) goto done; c = nvalloc(sizeof(TimerConfigProperty)); c->description = replace_characters(token, '_', ' '); token = strtok(NULL, ","); if (!token) goto done; if (nv_strcasecmp(token, "Yes")) { c->user_enabled = 1; } else if (nv_strcasecmp(token, "No")) { c->user_enabled = 0; } else { goto done; } token = strtok(NULL, ","); if (!token) goto done; parse_read_integer(token, &interval); c->interval = interval; c->next = conf->timers; conf->timers = c; } else { for (t = configPropertyTable, flag = 0; t->name; t++) { if (nv_strcasecmp(no_spaces, t->name)) { flag = t->flag; break; } } if (!flag) goto done; s++; if (nv_strcasecmp(s, "yes")) { conf->booleans |= flag; } else if (nv_strcasecmp(s, "no")) { conf->booleans &= ~flag; } else { goto done; } } ret = NV_TRUE; done: if ((ret != NV_TRUE) && c) { if (c->description) free(c->description); free(c); } if (no_spaces) free(no_spaces); return ret; } /* parse_config_property() */
static ParsedAttributeWrapper *parse_config_file(char *buf, const char *file, const int length, ConfigProperties *conf) { int line, has_data, current_tmp_len, len, n, ret; char *cur, *c, *comment, *tmp; ParsedAttributeWrapper *w; cur = buf; line = 1; current_tmp_len = 0; n = 0; w = NULL; tmp = NULL; while (cur) { c = cur; comment = NULL; has_data = NV_FALSE;; while (((c - buf) < length) && (*c != '\n') && (*c != '\0')) { if (comment) { c++; continue; } if (*c == '#') { comment = c; continue; } if (!isspace(*c)) has_data = NV_TRUE; c++; } if (has_data) { if (!comment) comment = c; len = comment - cur; /* grow the tmp buffer if it's too small */ if (len >= current_tmp_len) { current_tmp_len = len + 1; if (tmp) { free(tmp); } tmp = nvalloc(sizeof(char) * current_tmp_len); } strncpy (tmp, cur, len); tmp[len] = '\0'; /* first, see if this line is a config property */ if (!parse_config_property(file, tmp, conf)) { w = nvrealloc(w, sizeof(ParsedAttributeWrapper) * (n+1)); ret = nv_parse_attribute_string(tmp, NV_PARSER_ASSIGNMENT, &w[n].a); if (ret != NV_PARSER_STATUS_SUCCESS) { nv_error_msg("Error parsing configuration file '%s' on " "line %d: '%s' (%s).", file, line, tmp, nv_parse_strerror(ret)); goto failed; } w[n].line = line; n++; } } if (((c - buf) >= length) || (*c == '\0')) cur = NULL; else cur = c + 1; line++; } free(tmp); /* mark the end of the array */ w = nvrealloc(w, sizeof(ParsedAttributeWrapper) * (n+1)); w[n].line = -1; return w; failed: if (w) free(w); free(tmp); return NULL; } /* parse_config_file() */
DevicesPtr find_devices(Options *op) { DevicesPtr pDevices = NULL; DisplayDevicePtr pDisplayDevice; int i, j, n, count = 0; unsigned int mask, bit; DeviceRec tmpDevice; NvCfgPciDevice *devs = NULL; NvCfgBool is_primary_device; NvCfgBool ret; char *lib_path; void *lib_handle; NvCfgBool (*__getDevices)(int *n, NvCfgDevice **devs); NvCfgBool (*__openDevice)(int bus, int slot, NvCfgDeviceHandle *handle); NvCfgBool (*__getPciDevices)(int *n, NvCfgPciDevice **devs); NvCfgBool (*__openPciDevice)(int domain, int bus, int slot, int function, NvCfgDeviceHandle *handle); NvCfgBool (*__getNumCRTCs)(NvCfgDeviceHandle handle, int *crtcs); NvCfgBool (*__getProductName)(NvCfgDeviceHandle handle, char **name); NvCfgBool (*__getDisplayDevices)(NvCfgDeviceHandle handle, unsigned int *display_device_mask); NvCfgBool (*__getEDID)(NvCfgDeviceHandle handle, unsigned int display_device, NvCfgDisplayDeviceInformation *info); NvCfgBool (*__isPrimaryDevice)(NvCfgDeviceHandle handle, NvCfgBool *is_primary_device); NvCfgBool (*__closeDevice)(NvCfgDeviceHandle handle); NvCfgBool (*__getDeviceUUID)(NvCfgDeviceHandle handle, char **uuid); /* dlopen() the nvidia-cfg library */ #define __LIB_NAME "libnvidia-cfg.so.1" if (op->nvidia_cfg_path) { lib_path = nvstrcat(op->nvidia_cfg_path, "/", __LIB_NAME, NULL); } else { lib_path = strdup(__LIB_NAME); } lib_handle = dlopen(lib_path, RTLD_NOW); nvfree(lib_path); if (!lib_handle) { nv_warning_msg("error opening %s: %s.", __LIB_NAME, dlerror()); 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 */ __GET_FUNC(__getDevices, "nvCfgGetDevices"); __GET_FUNC(__openDevice, "nvCfgOpenDevice"); __GET_FUNC(__getPciDevices, "nvCfgGetPciDevices"); __GET_FUNC(__openPciDevice, "nvCfgOpenPciDevice"); __GET_FUNC(__getNumCRTCs, "nvCfgGetNumCRTCs"); __GET_FUNC(__getProductName, "nvCfgGetProductName"); __GET_FUNC(__getDisplayDevices, "nvCfgGetDisplayDevices"); __GET_FUNC(__getEDID, "nvCfgGetEDID"); __GET_FUNC(__closeDevice, "nvCfgCloseDevice"); __GET_FUNC(__getDeviceUUID, "nvCfgGetDeviceUUID"); /* optional functions */ __isPrimaryDevice = dlsym(lib_handle, "nvCfgIsPrimaryDevice"); if (__getPciDevices(&count, &devs) != NVCFG_TRUE) { return NULL; } if (count == 0) return NULL; pDevices = nvalloc(sizeof(DevicesRec)); pDevices->devices = nvalloc(sizeof(DeviceRec) * count); pDevices->nDevices = count; for (i = 0; i < count; i++) { pDevices->devices[i].dev = devs[i]; if (__openPciDevice(devs[i].domain, devs[i].bus, devs[i].slot, 0, &(pDevices->devices[i].handle)) != NVCFG_TRUE) { goto fail; } if (__getNumCRTCs(pDevices->devices[i].handle, &pDevices->devices[i].crtcs) != NVCFG_TRUE) { goto fail; } if (__getProductName(pDevices->devices[i].handle, &pDevices->devices[i].name) != NVCFG_TRUE) { /* This call may fail with little impact to the Device section */ pDevices->devices[i].name = NULL; } if (__getDeviceUUID(pDevices->devices[i].handle, &pDevices->devices[i].uuid) != NVCFG_TRUE) { goto fail; } if (__getDisplayDevices(pDevices->devices[i].handle, &mask) != NVCFG_TRUE) { goto fail; } pDevices->devices[i].displayDeviceMask = mask; /* count the number of display devices */ for (n = j = 0; j < 32; j++) { if (mask & (1 << j)) n++; } pDevices->devices[i].nDisplayDevices = n; if (n) { /* allocate the info array of the right size */ pDevices->devices[i].displayDevices = nvalloc(sizeof(DisplayDeviceRec) * n); /* fill in the info array */ for (n = j = 0; j < 32; j++) { bit = 1 << j; if (!(bit & mask)) continue; pDisplayDevice = &pDevices->devices[i].displayDevices[n]; pDisplayDevice->mask = bit; if (__getEDID(pDevices->devices[i].handle, bit, &pDisplayDevice->info) != NVCFG_TRUE) { pDisplayDevice->info_valid = FALSE; } else { pDisplayDevice->info_valid = TRUE; } n++; } } else { pDevices->devices[i].displayDevices = NULL; } if ((i != 0) && (__isPrimaryDevice != NULL) && (__isPrimaryDevice(pDevices->devices[i].handle, &is_primary_device) == NVCFG_TRUE) && (is_primary_device == NVCFG_TRUE)) { memcpy(&tmpDevice, &pDevices->devices[0], sizeof(DeviceRec)); memcpy(&pDevices->devices[0], &pDevices->devices[i], sizeof(DeviceRec)); memcpy(&pDevices->devices[i], &tmpDevice, sizeof(DeviceRec)); } ret = __closeDevice(pDevices->devices[i].handle); pDevices->devices[i].handle = NULL; if (ret != NVCFG_TRUE) { goto fail; } } goto done; fail: 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 */ if (pDevices->devices[i].handle) { __closeDevice(pDevices->devices[i].handle); } } free_devices(pDevices); pDevices = NULL; /* fall through */ done: if (devs) free(devs); return pDevices; } /* find_devices() */
static int disable_separate_x_screens(Options *op, XConfigPtr config, XConfigLayoutPtr layout) { XConfigScreenPtr screen, *screenlist = NULL; XConfigAdjacencyPtr adj; int i, nscreens = 0; /* 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) { nv_error_msg("Unable to find screen '%s'.", op->screen); return FALSE; } screenlist = nvalloc(sizeof(XConfigScreenPtr)); screenlist[0] = screen; nscreens = 1; } else { for (adj = layout->adjacencies; adj; adj = adj->next) { nscreens++; screenlist = realloc(screenlist, sizeof(XConfigScreenPtr) * nscreens); screenlist[nscreens-1] = adj->screen; } } /* * step 2: limit the list to screens that have a BusID; parse the busIDs * while we're at it */ 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, &slot, &scratch)) { // this screen has a valid busid } else { screenlist[i] = NULL; } } /* step 3 */ clean_screen_list(screenlist, config, nscreens); /* step 4: 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); return TRUE; } /* disable_separate_x_screens() */