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 */
XNVCTRLCheckTargetData(Display * dpy,XExtDisplayInfo * info,int * target_type,int * target_id)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
XNVCTRLQueryExtension(Display * dpy,int * event_basep,int * error_basep)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
XNVCTRLQueryVersion(Display * dpy,int * major,int * minor)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
XNVCTRLIsNvScreen(Display * dpy,int screen)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
XNVCTRLQueryTargetStringAttribute(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,char ** ptr)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
XNVCTRLQueryStringAttribute(Display * dpy,int screen,unsigned int display_mask,unsigned int attribute,char ** ptr)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
VA_NVCTRLQueryDirectRenderingCapable(Display * dpy,int screen,Bool * isCapable)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
VA_NVCTRLGetClientDriverName(Display * dpy,int screen,int * ddxDriverMajorVersion,int * ddxDriverMinorVersion,int * ddxDriverPatchVersion,char ** clientDriverName)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