1 /* 2 * Copyright (c) 2008 NVIDIA, Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24 #define _GNU_SOURCE 1 25 #include <string.h> 26 27 #define NEED_REPLIES 28 #include <stdlib.h> 29 #include <X11/Xlibint.h> 30 #include <X11/Xutil.h> 31 #include <X11/extensions/Xext.h> 32 #include <X11/extensions/extutil.h> 33 #include "va_nvctrl.h" 34 35 #define NV_CONTROL_ERRORS 0 36 #define NV_CONTROL_EVENTS 5 37 #define NV_CONTROL_NAME "NV-CONTROL" 38 39 #define NV_CTRL_TARGET_TYPE_X_SCREEN 0 40 #define NV_CTRL_TARGET_TYPE_GPU 1 41 #define NV_CTRL_TARGET_TYPE_FRAMELOCK 2 42 #define NV_CTRL_TARGET_TYPE_VCSC 3 /* Visual Computing System */ 43 44 #define NV_CTRL_STRING_NVIDIA_DRIVER_VERSION 3 /* R--G */ 45 46 #define X_nvCtrlQueryExtension 0 47 #define X_nvCtrlIsNv 1 48 #define X_nvCtrlQueryStringAttribute 4 49 50 typedef struct { 51 CARD8 reqType; 52 CARD8 nvReqType; 53 CARD16 length B16; 54 } xnvCtrlQueryExtensionReq; 55 #define sz_xnvCtrlQueryExtensionReq 4 56 57 typedef struct { 58 BYTE type; /* X_Reply */ 59 CARD8 padb1; 60 CARD16 sequenceNumber B16; 61 CARD32 length B32; 62 CARD16 major B16; 63 CARD16 minor B16; 64 CARD32 padl4 B32; 65 CARD32 padl5 B32; 66 CARD32 padl6 B32; 67 CARD32 padl7 B32; 68 CARD32 padl8 B32; 69 } xnvCtrlQueryExtensionReply; 70 #define sz_xnvCtrlQueryExtensionReply 32 71 72 typedef struct { 73 CARD8 reqType; 74 CARD8 nvReqType; 75 CARD16 length B16; 76 CARD32 screen B32; 77 } xnvCtrlIsNvReq; 78 #define sz_xnvCtrlIsNvReq 8 79 80 typedef struct { 81 BYTE type; /* X_Reply */ 82 CARD8 padb1; 83 CARD16 sequenceNumber B16; 84 CARD32 length B32; 85 CARD32 isnv B32; 86 CARD32 padl4 B32; 87 CARD32 padl5 B32; 88 CARD32 padl6 B32; 89 CARD32 padl7 B32; 90 CARD32 padl8 B32; 91 } xnvCtrlIsNvReply; 92 #define sz_xnvCtrlIsNvReply 32 93 94 typedef struct { 95 CARD8 reqType; 96 CARD8 nvReqType; 97 CARD16 length B16; 98 CARD16 target_id B16; /* X screen number or GPU number */ 99 CARD16 target_type B16; /* X screen or GPU */ 100 CARD32 display_mask B32; 101 CARD32 attribute B32; 102 } xnvCtrlQueryStringAttributeReq; 103 #define sz_xnvCtrlQueryStringAttributeReq 16 104 105 typedef struct { 106 BYTE type; 107 BYTE pad0; 108 CARD16 sequenceNumber B16; 109 CARD32 length B32; 110 CARD32 flags B32; 111 CARD32 n B32; /* Length of string */ 112 CARD32 pad4 B32; 113 CARD32 pad5 B32; 114 CARD32 pad6 B32; 115 CARD32 pad7 B32; 116 } xnvCtrlQueryStringAttributeReply; 117 #define sz_xnvCtrlQueryStringAttributeReply 32 118 119 #define NVCTRL_EXT_NEED_CHECK (XPointer)(~0) 120 #define NVCTRL_EXT_NEED_NOTHING (XPointer)(0) 121 #define NVCTRL_EXT_NEED_TARGET_SWAP (XPointer)(1) 122 123 static XExtensionInfo _nvctrl_ext_info_data; 124 static XExtensionInfo *nvctrl_ext_info = &_nvctrl_ext_info_data; 125 static /* const */ char *nvctrl_extension_name = NV_CONTROL_NAME; 126 127 #define XNVCTRLCheckExtension(dpy,i,val) \ 128 XextCheckExtension (dpy, i, nvctrl_extension_name, val) 129 #define XNVCTRLSimpleCheckExtension(dpy,i) \ 130 XextSimpleCheckExtension (dpy, i, nvctrl_extension_name) 131 132 static int close_display(); 133 static /* const */ XExtensionHooks nvctrl_extension_hooks = { 134 NULL, /* create_gc */ 135 NULL, /* copy_gc */ 136 NULL, /* flush_gc */ 137 NULL, /* free_gc */ 138 NULL, /* create_font */ 139 NULL, /* free_font */ 140 close_display, /* close_display */ 141 NULL, /* wire_to_event */ 142 NULL, /* event_to_wire */ 143 NULL, /* error */ 144 NULL, /* error_string */ 145 }; 146 147 static XEXT_GENERATE_FIND_DISPLAY (find_display, nvctrl_ext_info, 148 nvctrl_extension_name, 149 &nvctrl_extension_hooks, 150 NV_CONTROL_EVENTS, NVCTRL_EXT_NEED_CHECK) 151 152 static XEXT_GENERATE_CLOSE_DISPLAY (close_display, nvctrl_ext_info) 153 154 static Bool XNVCTRLQueryVersion (Display *dpy, int *major, int *minor); 155 156 /* 157 * NV-CONTROL versions 1.8 and 1.9 pack the target_type and target_id 158 * fields in reversed order. In order to talk to one of these servers, 159 * we need to swap these fields. 160 */ 161 static void XNVCTRLCheckTargetData(Display *dpy, XExtDisplayInfo *info, 162 int *target_type, int *target_id) 163 { 164 /* Find out what the server's NV-CONTROL version is and 165 * setup for swapping if we need to. 166 */ 167 if (info->data == NVCTRL_EXT_NEED_CHECK) { 168 int major, minor; 169 170 if (XNVCTRLQueryVersion(dpy, &major, &minor)) { 171 if (major == 1 && 172 (minor == 8 || minor == 9)) { 173 info->data = NVCTRL_EXT_NEED_TARGET_SWAP; 174 } else { 175 info->data = NVCTRL_EXT_NEED_NOTHING; 176 } 177 } else { 178 info->data = NVCTRL_EXT_NEED_NOTHING; 179 } 180 } 181 182 /* We need to swap the target_type and target_id */ 183 if (info->data == NVCTRL_EXT_NEED_TARGET_SWAP) { 184 int tmp; 185 tmp = *target_type; 186 *target_type = *target_id; 187 *target_id = tmp; 188 } 189 } 190 191 192 static Bool XNVCTRLQueryExtension ( 193 Display *dpy, 194 int *event_basep, 195 int *error_basep 196 ){ 197 XExtDisplayInfo *info = find_display (dpy); 198 199 if (XextHasExtension(info)) { 200 if (event_basep) *event_basep = info->codes->first_event; 201 if (error_basep) *error_basep = info->codes->first_error; 202 return True; 203 } else { 204 return False; 205 } 206 } 207 208 209 static Bool XNVCTRLQueryVersion ( 210 Display *dpy, 211 int *major, 212 int *minor 213 ){ 214 XExtDisplayInfo *info = find_display (dpy); 215 xnvCtrlQueryExtensionReply rep; 216 xnvCtrlQueryExtensionReq *req; 217 218 if(!XextHasExtension(info)) 219 return False; 220 221 XNVCTRLCheckExtension (dpy, info, False); 222 223 LockDisplay (dpy); 224 GetReq (nvCtrlQueryExtension, req); 225 req->reqType = info->codes->major_opcode; 226 req->nvReqType = X_nvCtrlQueryExtension; 227 if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { 228 UnlockDisplay (dpy); 229 SyncHandle (); 230 return False; 231 } 232 if (major) *major = rep.major; 233 if (minor) *minor = rep.minor; 234 UnlockDisplay (dpy); 235 SyncHandle (); 236 return True; 237 } 238 239 240 static Bool XNVCTRLIsNvScreen ( 241 Display *dpy, 242 int screen 243 ){ 244 XExtDisplayInfo *info = find_display (dpy); 245 xnvCtrlIsNvReply rep; 246 xnvCtrlIsNvReq *req; 247 Bool isnv; 248 249 if(!XextHasExtension(info)) 250 return False; 251 252 XNVCTRLCheckExtension (dpy, info, False); 253 254 LockDisplay (dpy); 255 GetReq (nvCtrlIsNv, req); 256 req->reqType = info->codes->major_opcode; 257 req->nvReqType = X_nvCtrlIsNv; 258 req->screen = screen; 259 if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { 260 UnlockDisplay (dpy); 261 SyncHandle (); 262 return False; 263 } 264 isnv = rep.isnv; 265 UnlockDisplay (dpy); 266 SyncHandle (); 267 return isnv; 268 } 269 270 271 static Bool XNVCTRLQueryTargetStringAttribute ( 272 Display *dpy, 273 int target_type, 274 int target_id, 275 unsigned int display_mask, 276 unsigned int attribute, 277 char **ptr 278 ){ 279 XExtDisplayInfo *info = find_display (dpy); 280 xnvCtrlQueryStringAttributeReply rep; 281 xnvCtrlQueryStringAttributeReq *req; 282 Bool exists; 283 int length, numbytes, slop; 284 285 if (!ptr) return False; 286 287 if(!XextHasExtension(info)) 288 return False; 289 290 XNVCTRLCheckExtension (dpy, info, False); 291 XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id); 292 293 LockDisplay (dpy); 294 GetReq (nvCtrlQueryStringAttribute, req); 295 req->reqType = info->codes->major_opcode; 296 req->nvReqType = X_nvCtrlQueryStringAttribute; 297 req->target_type = target_type; 298 req->target_id = target_id; 299 req->display_mask = display_mask; 300 req->attribute = attribute; 301 if (!_XReply (dpy, (xReply *) &rep, 0, False)) { 302 UnlockDisplay (dpy); 303 SyncHandle (); 304 return False; 305 } 306 length = rep.length; 307 numbytes = rep.n; 308 slop = numbytes & 3; 309 *ptr = (char *) Xmalloc(numbytes); 310 if (! *ptr) { 311 _XEatData(dpy, length); 312 UnlockDisplay (dpy); 313 SyncHandle (); 314 return False; 315 } else { 316 _XRead(dpy, (char *) *ptr, numbytes); 317 if (slop) _XEatData(dpy, 4-slop); 318 } 319 exists = rep.flags; 320 UnlockDisplay (dpy); 321 SyncHandle (); 322 return exists; 323 } 324 325 static Bool XNVCTRLQueryStringAttribute ( 326 Display *dpy, 327 int screen, 328 unsigned int display_mask, 329 unsigned int attribute, 330 char **ptr 331 ){ 332 return XNVCTRLQueryTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN, 333 screen, display_mask, 334 attribute, ptr); 335 } 336 337 338 Bool VA_NVCTRLQueryDirectRenderingCapable( Display *dpy, int screen, 339 Bool *isCapable ) 340 { 341 int event_base; 342 int error_base; 343 344 if (isCapable) 345 *isCapable = False; 346 347 if (!XNVCTRLQueryExtension(dpy, &event_base, &error_base)) 348 return False; 349 350 if (isCapable && XNVCTRLIsNvScreen(dpy, screen)) 351 *isCapable = True; 352 353 return True; 354 } 355 356 Bool VA_NVCTRLGetClientDriverName( Display *dpy, int screen, 357 int *ddxDriverMajorVersion, int *ddxDriverMinorVersion, 358 int *ddxDriverPatchVersion, char **clientDriverName ) 359 { 360 if (ddxDriverMajorVersion) 361 *ddxDriverMajorVersion = 0; 362 if (ddxDriverMinorVersion) 363 *ddxDriverMinorVersion = 0; 364 if (ddxDriverPatchVersion) 365 *ddxDriverPatchVersion = 0; 366 if (clientDriverName) 367 *clientDriverName = NULL; 368 369 char *nvidia_driver_version = NULL; 370 if (!XNVCTRLQueryStringAttribute(dpy, screen, 0, NV_CTRL_STRING_NVIDIA_DRIVER_VERSION, &nvidia_driver_version)) 371 return False; 372 373 char *end, *str = nvidia_driver_version; 374 unsigned long v = strtoul(str, &end, 10); 375 if (end && end != str) { 376 if (ddxDriverMajorVersion) 377 *ddxDriverMajorVersion = v; 378 if (*(str = end) == '.') { 379 v = strtoul(str + 1, &end, 10); 380 if (end && end != str && (*end == '.' || *end == '\0')) { 381 if (ddxDriverMinorVersion) 382 *ddxDriverMinorVersion = v; 383 if (*(str = end) == '.') { 384 v = strtoul(str + 1, &end, 10); 385 if (end && end != str && *end == '\0') { 386 if (ddxDriverPatchVersion) 387 *ddxDriverPatchVersion = v; 388 } 389 } 390 } 391 } 392 } 393 Xfree(nvidia_driver_version); 394 395 if (clientDriverName) 396 *clientDriverName = strdup("nvidia"); 397 398 return True; 399 } 400