/* NVClock 0.8 - Linux overclocker for NVIDIA cards * * Copyright(C) 2001-2004 Roderick Colenbrander * * site: http://NVClock.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* This library was written at the end of 2003 before nvidia released the source to their NV-CONTROL library. / The working of the library was figured out using a small LD_PRELOAD library which captured various X request/reply messages / of the leaked nvidia-settings program. With the help of various other xfree86 extensions this library was written. / Ofcourse the library wasn't 100% bugfree as it was hard to figure out the meaning of everything. Most bugs were fixed / when nvidia opensourced their own library. Lots of things were done quite similar in both libraries and there were / only a few small bugs. They were mainly related to the reply of NVGetValidAttributeValues which contained info / if options were supported and if so what values it supported, if it was display specific .. */ #include #include #include #include #include #include #include #include "nvcontrol.h" static Bool wire_to_event (Display *dpy, XEvent *host, xEvent *wire); static /* const */ XExtensionHooks Hooks = { NULL, /* create_gc */ NULL, /* copy_gc */ NULL, /* flush_gc */ NULL, /* free_gc */ NULL, /* create_font */ NULL, /* free_font */ NULL, /* close_display */ wire_to_event, /* wire_to_event */ NULL, /* event_to_wire */ NULL, /* error */ NULL /* error_string */ }; XExtensionInfo *NV_extinfo = NULL; static XEXT_GENERATE_FIND_DISPLAY(NVFindDisplay,NV_extinfo,"NV-CONTROL", &Hooks,1,NULL); /* QueryExtension */ int NVQueryExtension(Display *dpy, int *event_base, int *error_base) { XExtDisplayInfo *dpyinfo = NVFindDisplay(dpy); if((NV_extinfo == NULL) || (dpyinfo == NULL)) { XMissingExtension(dpy, "NV-CONTROL"); return 0; } if(XextHasExtension(dpyinfo)) { *event_base = dpyinfo->codes->first_event; *error_base = dpyinfo->codes->first_error; return 1; } return 0; } /* QueryVersion */ int NVQueryVersion(Display *dpy, int *major, int *minor) { xNVQueryVersionReq *req; xNVQueryVersionReply rep; XExtDisplayInfo *dpyinfo = NVFindDisplay(dpy); if((NV_extinfo == NULL) || (dpyinfo == NULL)) { XMissingExtension(dpy, "NV-CONTROL"); return 0; } /* For some reason in the case an extension doesn't exist dpyinfo isn't NULL (atleast on this box) */ else if(dpyinfo->codes == 0) { XMissingExtension(dpy, "NV-CONTROL"); return 0; } else { LockDisplay(dpy); NVGetReq(QueryVersion, req); if(_XReply(dpy, (xReply*)&rep, 0, 1) != 0) { *major = rep.major & 65535; *minor = rep.minor & 65535; } UnlockDisplay(dpy); SyncHandle(); return 1; } } int NVGetAttribute(Display *dpy, int screen, unsigned int disp_mask, unsigned int option, int *value) { xNVGetAttributeReq *req; xNVGetAttributeReply rep; XExtDisplayInfo *dpyinfo = NVFindDisplay(dpy); if((NV_extinfo == NULL) || (dpyinfo == NULL)) { XMissingExtension(dpy, "NV-CONTROL"); return 0; } else { LockDisplay(dpy); NVGetReq(GetAttribute, req); req->disp_mask = disp_mask; req->screen = screen; req->option = option; if(_XReply(dpy, (xReply*)&rep, 0, 1) == 0) { UnlockDisplay(dpy); SyncHandle(); return 0; } UnlockDisplay(dpy); SyncHandle(); /* Return succes only when the option exists */ if(rep.flags) { *value = rep.value; return 1; } } return 0; } int NVGetStringAttribute(Display *dpy, int screen, unsigned int disp_mask, unsigned int option, char **res) { xNVGetStringAttributeReq *req; xNVGetStringAttributeReply rep; XExtDisplayInfo *dpyinfo = NVFindDisplay(dpy); if((NV_extinfo == NULL) || (dpyinfo == NULL)) { XMissingExtension(dpy, "NV-CONTROL"); return 0; } else { char *buf; LockDisplay(dpy); NVGetReq(GetStringAttribute, req); req->disp_mask = disp_mask; req->screen = screen; req->option = option; if(_XReply(dpy, (xReply*)&rep, 0, 0) != 0) { buf = malloc(rep.length << 2); if(buf != NULL) { _XRead(dpy, buf, rep.length << 2); UnlockDisplay(dpy); SyncHandle(); *res = buf; return 1; } } UnlockDisplay(dpy); SyncHandle(); return 0; } } int NVGetValidAttributeValues(Display *dpy, int screen, unsigned int disp_mask, unsigned int option, validated **out) { validated *res = malloc(sizeof(validated)); xNVGetValidAttributeValuesReq *req; xNVGetValidAttributeValuesReply rep; XExtDisplayInfo *dpyinfo = NVFindDisplay(dpy); if((NV_extinfo == NULL) || (dpyinfo == NULL)) { XMissingExtension(dpy, "NV-CONTROL"); return 0; } else { LockDisplay(dpy); NVGetReq(GetValidAttributeValues, req); req->disp_mask = disp_mask; req->screen = screen; req->option = option; if(_XReply(dpy, (xReply*)&rep, 0, 1) != 0) { res->type = rep.attr_type; res->flags = rep.flags; /* contains if the option is supported or not */ /* Option is not supported by this card, so return Null */ if(res->flags == 0) return 0; /* integer attribute */ if(rep.attr_type == 1) { /* Do nothing as there doesn't seem to be a limit */ } /* bitmask */ else if(res->type == 2) res->data1 = rep.data_bitmask; /* boolean */ else if(res->type == 3) { /* Do nothing, values 0 and 1 */ } /* range */ else if(rep.attr_type == 4) { res->data1 = rep.data_range_min; res->data2 = rep.data_range_max; } /* Another type of bitmask used for example for FSAA */ else if(rep.attr_type == 5) res->data1 = rep.data_bitmask; } *out = res; UnlockDisplay(dpy); SyncHandle(); } return 1; } void NVSetAttribute(Display *dpy, int screen, unsigned int disp_mask, unsigned int option, int value) { xNVSetAttributeReq *req; XExtDisplayInfo *dpyinfo = NVFindDisplay(dpy); if((NV_extinfo == NULL) || (dpyinfo == NULL)) { XMissingExtension(dpy, "NV-CONTROL"); } else { LockDisplay(dpy); NVGetReq(SetAttribute, req); req->disp_mask = disp_mask; req->screen = screen; req->option = option; req->value = value; UnlockDisplay(dpy); SyncHandle(); } /* make sure the attribute is indeed set */ _XFlush(dpy); } #define X_NVSelectNotify 6 int NVSelectNotify(Display *dpy, int screen, int type, Bool toggle) { xNVSelectNotifyReq *req; XExtDisplayInfo *dpyinfo = NVFindDisplay(dpy); if((NV_extinfo == NULL) || (dpyinfo == NULL)) { XMissingExtension(dpy, "NV-CONTROL"); return 0; } else { LockDisplay(dpy); NVGetReq(SelectNotify, req); req->screen = screen; req->type = type; req->toggle = toggle; UnlockDisplay(dpy); SyncHandle(); } return 1; } static Bool wire_to_event (Display *dpy, XEvent *host, xEvent *wire) { XExtDisplayInfo *dpyinfo = NVFindDisplay (dpy); NVEvent *re = (NVEvent *) host; nvEvent *event = (nvEvent *) wire; if((NV_extinfo == NULL) || (dpyinfo == NULL)) { XMissingExtension(dpy, "NV-CONTROL"); return False; } switch ((event->u.u.type & 0x7F) - dpyinfo->codes->first_event) { case 0: re->attribute_changed.type = event->u.u.type & 0x7F; re->attribute_changed.serial = _XSetLastRequestRead(dpy, (xGenericReply*) event); re->attribute_changed.send_event = ((event->u.u.type & 0x80) != 0); re->attribute_changed.dpy = dpy; re->attribute_changed.time = event->u.attribute_changed.time; re->attribute_changed.screen = event->u.attribute_changed.screen; re->attribute_changed.disp_mask = event->u.attribute_changed.disp_mask; re->attribute_changed.option = event->u.attribute_changed.option; re->attribute_changed.value = event->u.attribute_changed.value; break; default: return False; } return True; }