Home | History | Annotate | Download | only in x11
      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