Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright  2007 Red Hat, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is 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
     18  * THE 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  * Authors:
     24  *    Dave Airlie <airlied (at) redhat.com>
     25  *
     26  */
     27 
     28 #ifdef HAVE_CONFIG_H
     29 #include "config.h"
     30 #endif
     31 
     32 #include <errno.h>
     33 #include <sys/ioctl.h>
     34 #include <sys/mman.h>
     35 #include "xf86str.h"
     36 #include "X11/Xatom.h"
     37 #include "micmap.h"
     38 #include "xf86cmap.h"
     39 #include "xf86DDC.h"
     40 
     41 #include <xf86drm.h>
     42 #include "xf86Crtc.h"
     43 #include "via_driver.h"
     44 
     45 /* DPMS */
     46 #ifdef HAVE_XEXTPROTO_71
     47 #include <X11/extensions/dpmsconst.h>
     48 #else
     49 #define DPMS_SERVER
     50 #include <X11/extensions/dpms.h>
     51 #endif
     52 
     53 xf86CrtcPtr
     54 window_belongs_to_crtc(ScrnInfoPtr pScrn, int x, int y, int w, int h)
     55 {
     56     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
     57     int largest = 0, area = 0, i;
     58     BoxRec crtc_area, overlap;
     59     xf86CrtcPtr best = NULL;
     60 
     61     for (i = 0; i < xf86_config->num_crtc; i++) {
     62         xf86CrtcPtr crtc = xf86_config->crtc[i];
     63 
     64         if (crtc->enabled) {
     65             crtc_area.x1 = crtc->x;
     66             crtc_area.x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
     67             crtc_area.y1 = crtc->y;
     68             crtc_area.y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
     69             overlap.x1 = crtc_area.x1 > x ? crtc_area.x1 : x;
     70             overlap.x2 = crtc_area.x2 < x + w ? crtc_area.x2 : x + w;
     71             overlap.y1 = crtc_area.y1 > y ? crtc_area.y1 : y;
     72             overlap.y2 = crtc_area.y2 < y ? crtc_area.y2 : y + h;
     73 
     74             if (overlap.x1 >= overlap.x2 || overlap.y1 >= overlap.y2)
     75                 overlap.x1 = overlap.x2 = overlap.y1 = overlap.y2 = 0;
     76 
     77             area = (overlap.x2 - overlap.x1) * (overlap.y2 - overlap.y1);
     78             if (area > largest) {
     79                 area = largest;
     80                 best = crtc;
     81             }
     82         }
     83     }
     84     return best;
     85 }
     86 
     87 static void
     88 drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
     89                             DisplayModePtr mode)
     90 {
     91     memset(mode, 0, sizeof(DisplayModeRec));
     92     mode->status = MODE_OK;
     93 
     94     mode->Clock = kmode->clock;
     95 
     96     mode->HDisplay = kmode->hdisplay;
     97     mode->HSyncStart = kmode->hsync_start;
     98     mode->HSyncEnd = kmode->hsync_end;
     99     mode->HTotal = kmode->htotal;
    100     mode->HSkew = kmode->hskew;
    101 
    102     mode->VDisplay = kmode->vdisplay;
    103     mode->VSyncStart = kmode->vsync_start;
    104     mode->VSyncEnd = kmode->vsync_end;
    105     mode->VTotal = kmode->vtotal;
    106     mode->VScan = kmode->vscan;
    107 
    108     mode->Flags = kmode->flags; //& FLAG_BITS;
    109     mode->name = strdup(kmode->name);
    110 
    111     if (kmode->type & DRM_MODE_TYPE_DRIVER)
    112         mode->type = M_T_DRIVER;
    113     if (kmode->type & DRM_MODE_TYPE_PREFERRED)
    114         mode->type |= M_T_PREFERRED;
    115     xf86SetModeCrtc(mode, pScrn->adjustFlags);
    116 }
    117 
    118 static void
    119 drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
    120                         DisplayModePtr mode)
    121 {
    122     memset(kmode, 0, sizeof(*kmode));
    123 
    124     kmode->clock = mode->Clock;
    125     kmode->hdisplay = mode->HDisplay;
    126     kmode->hsync_start = mode->HSyncStart;
    127     kmode->hsync_end = mode->HSyncEnd;
    128     kmode->htotal = mode->HTotal;
    129     kmode->hskew = mode->HSkew;
    130 
    131     kmode->vdisplay = mode->VDisplay;
    132     kmode->vsync_start = mode->VSyncStart;
    133     kmode->vsync_end = mode->VSyncEnd;
    134     kmode->vtotal = mode->VTotal;
    135     kmode->vscan = mode->VScan;
    136 
    137     kmode->flags = mode->Flags; //& FLAG_BITS;
    138     if (mode->name)
    139         strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
    140     kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
    141 }
    142 
    143 static void
    144 drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
    145 {
    146 #if 0
    147     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
    148     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    149     drmmode_ptr drmmode = drmmode_crtc->drmmode;
    150 
    151     /* bonghits in the randr 1.2 - uses dpms to disable crtc - bad buzz */
    152     if (mode == DPMSModeOff) {
    153         drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    154 	                    0, 0, 0, NULL, 0, NULL);
    155     }
    156 #endif
    157 }
    158 
    159 static Bool
    160 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
    161                         Rotation rotation, int x, int y)
    162 {
    163     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
    164     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    165     drmmode_ptr drmmode = drmmode_crtc->drmmode;
    166     ScrnInfoPtr pScrn = crtc->scrn;
    167     int output_count = 0, ret, i;
    168     uint32_t *output_ids = NULL;
    169     drmModeModeInfo kmode;
    170 
    171     if (!mode || !xf86CrtcRotate(crtc))
    172         return FALSE;
    173 
    174     output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
    175     if (!output_ids)
    176         return FALSE;
    177 
    178     for (i = 0; i < xf86_config->num_output; i++) {
    179         xf86OutputPtr output = xf86_config->output[i];
    180         drmmode_output_private_ptr drmmode_output;
    181 
    182         if (output->crtc != crtc)
    183             continue;
    184 
    185         drmmode_output = output->driver_private;
    186         output_ids[output_count] = drmmode_output->mode_output->connector_id;
    187         output_count++;
    188     }
    189 
    190     drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
    191 
    192     if (drmmode->fb_id == 0) {
    193         ret = drmModeAddFB(drmmode->fd, pScrn->virtualX, pScrn->virtualY,
    194                             pScrn->depth, pScrn->bitsPerPixel,
    195                             drmmode->front_bo->pitch,
    196                             drmmode->front_bo->handle,
    197                             &drmmode->fb_id);
    198         if (ret < 0) {
    199             ErrorF("failed to add fb %d\n", ret);
    200             goto done;
    201         }
    202     }
    203 
    204     ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    205                          drmmode->fb_id, x, y, output_ids, output_count, &kmode);
    206     if (ret) {
    207         xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "failed to set mode: %s",
    208                    strerror(-ret));
    209         goto done;
    210     }
    211 
    212     if (crtc->scrn->pScreen)
    213         xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
    214 
    215     /* go through all the outputs and force DPMS them back on? */
    216     for (i = 0; i < xf86_config->num_output; i++) {
    217         xf86OutputPtr output = xf86_config->output[i];
    218 
    219         if (output->crtc != crtc)
    220             continue;
    221 
    222         output->funcs->dpms(output, DPMSModeOn);
    223     }
    224 
    225 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0)
    226     crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
    227                            crtc->gamma_blue, crtc->gamma_size);
    228 #endif
    229 
    230     if (pScrn->pScreen && drmmode->hwcursor)
    231 #ifdef HAVE_XF86_CURSOR_RESET_CURSOR
    232         xf86CursorResetCursor(pScrn->pScreen);
    233 #else
    234         xf86_reload_cursors(pScrn->pScreen);
    235 #endif
    236 done:
    237     free(output_ids);
    238     return (ret < 0 ? FALSE : TRUE);
    239 }
    240 
    241 static void
    242 drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
    243 {
    244 }
    245 
    246 static void
    247 drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
    248 {
    249     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    250     drmmode_ptr drmmode = drmmode_crtc->drmmode;
    251 
    252     drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
    253 }
    254 
    255 static void
    256 drmmode_hide_cursor (xf86CrtcPtr crtc)
    257 {
    258     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
    259     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    260     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
    261     drmmode_ptr drmmode = drmmode_crtc->drmmode;
    262 
    263     drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
    264                         cursor_info->MaxWidth, cursor_info->MaxHeight);
    265 }
    266 
    267 static void
    268 drmmode_show_cursor (xf86CrtcPtr crtc)
    269 {
    270     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
    271     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    272     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
    273     uint32_t handle = drmmode_crtc->cursor_bo->handle;
    274     drmmode_ptr drmmode = drmmode_crtc->drmmode;
    275 
    276     drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle,
    277                         cursor_info->MaxWidth, cursor_info->MaxHeight);
    278 }
    279 
    280 static void
    281 drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
    282 {
    283     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
    284     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    285     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
    286     uint32_t handle = drmmode_crtc->cursor_bo->handle, *ptr;
    287 
    288     /* cursor should be mapped already */
    289     ptr = drm_bo_map(crtc->scrn, drmmode_crtc->cursor_bo);
    290     memset(ptr, 0x00, drmmode_crtc->cursor_bo->size);
    291     memcpy(ptr, image, drmmode_crtc->cursor_bo->size);
    292     drm_bo_unmap(crtc->scrn, drmmode_crtc->cursor_bo);
    293 
    294     if (drmModeSetCursor(drmmode_crtc->drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    295                             handle, cursor_info->MaxWidth, cursor_info->MaxHeight)) {
    296         drmmode_ptr drmmode = drmmode_crtc->drmmode;
    297 
    298         cursor_info->MaxWidth = cursor_info->MaxHeight = 0;
    299         drmmode->hwcursor = FALSE;
    300     }
    301 }
    302 
    303 static void
    304 drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
    305                       uint16_t *blue, int size)
    306 {
    307     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
    308     drmmode_ptr drmmode = drmmode_crtc->drmmode;
    309 
    310     drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
    311                         size, red, green, blue);
    312 }
    313 
    314 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
    315     .dpms                   = drmmode_crtc_dpms,
    316     .set_mode_major         = drmmode_set_mode_major,
    317     .set_cursor_colors      = drmmode_set_cursor_colors,
    318     .set_cursor_position    = drmmode_set_cursor_position,
    319     .show_cursor            = drmmode_show_cursor,
    320     .hide_cursor            = drmmode_hide_cursor,
    321     .load_cursor_argb       = drmmode_load_cursor_argb,
    322     .gamma_set              = drmmode_crtc_gamma_set,
    323     .destroy                = NULL,
    324 };
    325 
    326 static void
    327 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
    328 {
    329     drmmode_crtc_private_ptr drmmode_crtc;
    330     xf86CrtcPtr crtc;
    331 
    332     crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
    333     if (crtc == NULL)
    334         return;
    335 
    336     drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
    337     drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]);
    338     drmmode_crtc->drmmode = drmmode;
    339     crtc->driver_private = drmmode_crtc;
    340 }
    341 
    342 /*
    343  * Handle KMS xf86Outputs
    344  */
    345 static Bool
    346 drmmode_property_ignore(drmModePropertyPtr prop)
    347 {
    348     if (!prop)
    349         return TRUE;
    350 
    351     /* ignore blob prop */
    352     if (prop->flags & DRM_MODE_PROP_BLOB)
    353         return TRUE;
    354 
    355     /* ignore standard property */
    356     if (!strcmp(prop->name, "EDID") ||
    357         !strcmp(prop->name, "DPMS"))
    358         return TRUE;
    359 
    360     return FALSE;
    361 }
    362 
    363 static void
    364 drmmode_output_dpms(xf86OutputPtr output, int mode)
    365 {
    366 	drmmode_output_private_ptr drmmode_output = output->driver_private;
    367 	drmModeConnectorPtr koutput = drmmode_output->mode_output;
    368 	drmmode_ptr drmmode = drmmode_output->drmmode;
    369 
    370 	drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
    371 	                            drmmode_output->dpms_enum_id, mode);
    372 	return;
    373 }
    374 
    375 static void
    376 drmmode_output_create_resources(xf86OutputPtr output)
    377 {
    378     drmmode_output_private_ptr drmmode_output = output->driver_private;
    379     drmModeConnectorPtr mode_output = drmmode_output->mode_output;
    380     drmmode_ptr drmmode = drmmode_output->drmmode;
    381     drmModePropertyPtr drmmode_prop;
    382     int i, j, err;
    383 
    384     drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
    385     if (!drmmode_output->props)
    386         return;
    387 
    388     drmmode_output->num_props = 0;
    389     for (i = 0, j = 0; i < mode_output->count_props; i++) {
    390 	    drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
    391 
    392         if (drmmode_property_ignore(drmmode_prop)) {
    393 	        drmModeFreeProperty(drmmode_prop);
    394             continue;
    395         }
    396         drmmode_output->props[j].mode_prop = drmmode_prop;
    397         drmmode_output->props[j].value = mode_output->prop_values[i];
    398         drmmode_output->num_props++;
    399         j++;
    400     }
    401 
    402     for (i = 0; i < drmmode_output->num_props; i++) {
    403         drmmode_prop_ptr p = &drmmode_output->props[i];
    404         drmmode_prop = p->mode_prop;
    405 
    406         if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
    407             INT32 range[2];
    408             INT32 value = p->value;
    409 
    410             p->num_atoms = 1;
    411             p->atoms = calloc(p->num_atoms, sizeof(Atom));
    412             if (!p->atoms)
    413                 continue;
    414             p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
    415             range[0] = drmmode_prop->values[0];
    416             range[1] = drmmode_prop->values[1];
    417             err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
    418                                             FALSE, TRUE,
    419                                             drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
    420                                             2, range);
    421             if (err != 0) {
    422                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
    423                             "RRConfigureOutputProperty error, %d\n", err);
    424             }
    425             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
    426                                         XA_INTEGER, 32, PropModeReplace, 1,
    427                                         &value, FALSE, TRUE);
    428             if (err != 0) {
    429                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
    430                             "RRChangeOutputProperty error, %d\n", err);
    431             }
    432 
    433         } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
    434             p->num_atoms = drmmode_prop->count_enums + 1;
    435             p->atoms = calloc(p->num_atoms, sizeof(Atom));
    436             if (!p->atoms)
    437                 continue;
    438 
    439             p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
    440             for (j = 1; j <= drmmode_prop->count_enums; j++) {
    441                 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
    442 
    443                 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
    444             }
    445             err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
    446                                             FALSE, FALSE,
    447                                             drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
    448                                             p->num_atoms - 1, (INT32 *)&p->atoms[1]);
    449             if (err != 0) {
    450                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
    451                             "RRConfigureOutputProperty error, %d\n", err);
    452             }
    453 
    454             for (j = 0; j < drmmode_prop->count_enums; j++)
    455                 if (drmmode_prop->enums[j].value == p->value)
    456                     break;
    457 
    458             /* there's always a matching value */
    459             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
    460                                         XA_ATOM, 32, PropModeReplace, 1,
    461                                         &p->atoms[j+1], FALSE, TRUE);
    462             if (err != 0) {
    463                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
    464                             "RRChangeOutputProperty error, %d\n", err);
    465             }
    466         }
    467     }
    468 }
    469 
    470 static Bool
    471 drmmode_output_set_property(xf86OutputPtr output, Atom property,
    472                             RRPropertyValuePtr value)
    473 {
    474     drmmode_output_private_ptr drmmode_output = output->driver_private;
    475     drmmode_ptr drmmode = drmmode_output->drmmode;
    476     int i;
    477 
    478     for (i = 0; i < drmmode_output->num_props; i++) {
    479         drmmode_prop_ptr p = &drmmode_output->props[i];
    480 
    481         if (p->atoms[0] != property)
    482             continue;
    483 
    484         if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
    485             uint32_t val;
    486 
    487             if (value->type != XA_INTEGER || value->format != 32 ||
    488                 value->size != 1)
    489                 return FALSE;
    490             val = *(uint32_t *)value->data;
    491 
    492             drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
    493                                         p->mode_prop->prop_id, (uint64_t)val);
    494             return TRUE;
    495         } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
    496             const char *name;
    497             Atom atom;
    498             int	j;
    499 
    500             if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
    501                 return FALSE;
    502             memcpy(&atom, value->data, 4);
    503             name = NameForAtom(atom);
    504 
    505             /* search for matching name string, then set its value down */
    506             for (j = 0; j < p->mode_prop->count_enums; j++) {
    507                 if (!strcmp(p->mode_prop->enums[j].name, name)) {
    508                     drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
    509                     p->mode_prop->prop_id, p->mode_prop->enums[j].value);
    510                     return TRUE;
    511                 }
    512             }
    513         }
    514     }
    515     return TRUE;
    516 }
    517 
    518 static Bool
    519 drmmode_output_get_property(xf86OutputPtr output, Atom property)
    520 {
    521     return TRUE;
    522 }
    523 
    524 static xf86OutputStatus
    525 drmmode_output_detect(xf86OutputPtr output)
    526 {
    527     /* go to the hw and retrieve a new output struct */
    528     drmmode_output_private_ptr drmmode_output = output->driver_private;
    529     drmmode_ptr drmmode = drmmode_output->drmmode;
    530     xf86OutputStatus status;
    531 
    532     drmModeFreeConnector(drmmode_output->mode_output);
    533     drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
    534 
    535     switch (drmmode_output->mode_output->connection) {
    536     case DRM_MODE_CONNECTED:
    537         status = XF86OutputStatusConnected;
    538         break;
    539     case DRM_MODE_DISCONNECTED:
    540         status = XF86OutputStatusDisconnected;
    541         break;
    542     default:
    543     case DRM_MODE_UNKNOWNCONNECTION:
    544         status = XF86OutputStatusUnknown;
    545         break;
    546     }
    547     return status;
    548 }
    549 
    550 static Bool
    551 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
    552 {
    553     return MODE_OK;
    554 }
    555 
    556 static DisplayModePtr
    557 drmmode_output_get_modes(xf86OutputPtr output)
    558 {
    559     drmmode_output_private_ptr drmmode_output = output->driver_private;
    560     drmModeConnectorPtr koutput = drmmode_output->mode_output;
    561     drmmode_ptr drmmode = drmmode_output->drmmode;
    562     DisplayModePtr Modes = NULL, Mode;
    563     drmModePropertyPtr props;
    564     xf86MonPtr mon = NULL;
    565     int i;
    566 
    567     /* look for an EDID property */
    568     for (i = 0; i < koutput->count_props; i++) {
    569         props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
    570         if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
    571             if (!strcmp(props->name, "EDID")) {
    572                 if (drmmode_output->edid_blob)
    573                     drmModeFreePropertyBlob(drmmode_output->edid_blob);
    574                 drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
    575             }
    576             drmModeFreeProperty(props);
    577         }
    578     }
    579 
    580     if (drmmode_output->edid_blob) {
    581         mon = xf86InterpretEDID(output->scrn->scrnIndex,
    582                                 drmmode_output->edid_blob->data);
    583         if (mon && drmmode_output->edid_blob->length > 128)
    584             mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
    585     }
    586     xf86OutputSetEDID(output, mon);
    587 
    588     /* modes should already be available */
    589     for (i = 0; i < koutput->count_modes; i++) {
    590         Mode = xnfalloc(sizeof(DisplayModeRec));
    591 
    592         drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
    593         Modes = xf86ModesAdd(Modes, Mode);
    594 
    595     }
    596     return Modes;
    597 }
    598 
    599 static void
    600 drmmode_output_destroy(xf86OutputPtr output)
    601 {
    602     drmmode_output_private_ptr drmmode_output = output->driver_private;
    603     int i;
    604 
    605     if (drmmode_output->edid_blob)
    606         drmModeFreePropertyBlob(drmmode_output->edid_blob);
    607 
    608     for (i = 0; i < drmmode_output->num_props; i++) {
    609         drmModeFreeProperty(drmmode_output->props[i].mode_prop);
    610         free(drmmode_output->props[i].atoms);
    611     }
    612 
    613     for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
    614         drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
    615         free(drmmode_output->mode_encoders);
    616     }
    617     free(drmmode_output->props);
    618     drmModeFreeConnector(drmmode_output->mode_output);
    619     free(drmmode_output);
    620     output->driver_private = NULL;
    621 }
    622 
    623 static const xf86OutputFuncsRec drmmode_output_funcs = {
    624     .dpms               = drmmode_output_dpms,
    625     .create_resources   = drmmode_output_create_resources,
    626 #ifdef RANDR_12_INTERFACE
    627     .set_property       = drmmode_output_set_property,
    628     .get_property       = drmmode_output_get_property,
    629 #endif
    630     .detect             = drmmode_output_detect,
    631     .mode_valid         = drmmode_output_mode_valid,
    632     .get_modes          = drmmode_output_get_modes,
    633     .destroy            = drmmode_output_destroy
    634 };
    635 
    636 static int subpixel_conv_table[7] = {
    637     0,
    638     SubPixelUnknown,
    639     SubPixelHorizontalRGB,
    640     SubPixelHorizontalBGR,
    641     SubPixelVerticalRGB,
    642     SubPixelVerticalBGR,
    643     SubPixelNone
    644 };
    645 
    646 const char *output_names[] = {
    647     "None",
    648     "VGA",
    649     "DVI",
    650     "DVI",
    651     "DVI",
    652     "Composite",
    653     "S-video",
    654     "LVDS",
    655     "CTV",
    656     "DIN",
    657     "DisplayPort",
    658     "HDMI",
    659     "HDMI",
    660     "TV",
    661     "eDP"
    662 };
    663 
    664 static void
    665 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
    666 {
    667     xf86OutputPtr output;
    668     drmModeConnectorPtr koutput;
    669     drmModeEncoderPtr *kencoders = NULL;
    670     drmmode_output_private_ptr drmmode_output;
    671     drmModePropertyPtr props;
    672     char name[32];
    673     int i;
    674 
    675     koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
    676     if (!koutput)
    677         return;
    678 
    679     kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
    680     if (!kencoders) {
    681         goto out_free_encoders;
    682     }
    683 
    684     for (i = 0; i < koutput->count_encoders; i++) {
    685         kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
    686         if (!kencoders[i]) {
    687             goto out_free_encoders;
    688         }
    689     }
    690 
    691     /* need to do smart conversion here for compat with non-kms ATI driver */
    692     snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
    693 
    694     output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
    695     if (!output) {
    696         goto out_free_encoders;
    697     }
    698 
    699     drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
    700     if (!drmmode_output) {
    701         xf86OutputDestroy(output);
    702         goto out_free_encoders;
    703     }
    704 
    705     drmmode_output->output_id = drmmode->mode_res->connectors[num];
    706     drmmode_output->mode_output = koutput;
    707     drmmode_output->mode_encoders = kencoders;
    708     drmmode_output->drmmode = drmmode;
    709     output->mm_width = koutput->mmWidth;
    710     output->mm_height = koutput->mmHeight;
    711 
    712     output->subpixel_order = subpixel_conv_table[koutput->subpixel];
    713     output->interlaceAllowed = TRUE;
    714     output->doubleScanAllowed = TRUE;
    715     output->driver_private = drmmode_output;
    716 
    717     output->possible_crtcs = 0x7f;
    718     for (i = 0; i < koutput->count_encoders; i++)
    719         output->possible_crtcs &= kencoders[i]->possible_crtcs;
    720 
    721     /* work out the possible clones later */
    722     output->possible_clones = 0;
    723 
    724     for (i = 0; i < koutput->count_props; i++) {
    725         props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
    726         if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
    727             if (!strcmp(props->name, "DPMS")) {
    728                 drmmode_output->dpms_enum_id = koutput->props[i];
    729                 drmModeFreeProperty(props);
    730                 break;
    731             }
    732             drmModeFreeProperty(props);
    733         }
    734     }
    735 
    736     return;
    737 out_free_encoders:
    738     if (kencoders){
    739         for (i = 0; i < koutput->count_encoders; i++)
    740             drmModeFreeEncoder(kencoders[i]);
    741         free(kencoders);
    742     }
    743     drmModeFreeConnector(koutput);
    744 }
    745 
    746 uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
    747 {
    748     drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout;
    749     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    750     xf86OutputPtr clone_output;
    751     int index_mask = 0, i;
    752 
    753     if (drmmode_output->enc_clone_mask == 0)
    754         return index_mask;
    755 
    756     for (i = 0; i < xf86_config->num_output; i++) {
    757         clone_output = xf86_config->output[i];
    758         clone_drmout = clone_output->driver_private;
    759         if (output == clone_output)
    760             continue;
    761         if (clone_drmout->enc_mask == 0)
    762             continue;
    763         if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
    764             index_mask |= (1 << i);
    765     }
    766     return index_mask;
    767 }
    768 
    769 static void
    770 drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
    771 {
    772     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
    773     int i, j;
    774 
    775     for (i = 0; i < xf86_config->num_output; i++) {
    776         xf86OutputPtr output = xf86_config->output[i];
    777         drmmode_output_private_ptr drmmode_output;
    778 
    779         drmmode_output = output->driver_private;
    780         drmmode_output->enc_clone_mask = 0xff;
    781         /* and all the possible encoder clones for this output together */
    782         for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) {
    783             int k;
    784 
    785             for (k = 0; k < drmmode->mode_res->count_encoders; k++) {
    786                 if (drmmode->mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id)
    787                     drmmode_output->enc_mask |= (1 << k);
    788             }
    789 
    790             drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones;
    791         }
    792     }
    793 
    794     for (i = 0; i < xf86_config->num_output; i++) {
    795         xf86OutputPtr output = xf86_config->output[i];
    796         output->possible_clones = find_clones(scrn, output);
    797     }
    798 }
    799 
    800 Bool KMSCrtcInit(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
    801 {
    802     int i;
    803 
    804     DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "KMSCrtcInit\n"));
    805 
    806     drmmode->scrn = pScrn;
    807     drmmode->mode_res = drmModeGetResources(drmmode->fd);
    808     if (!drmmode->mode_res)
    809         return FALSE;
    810 
    811     xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height);
    812     for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
    813         if (!xf86IsEntityShared(pScrn->entityList[0]) || pScrn->confScreen->device->screen == i)
    814             drmmode_crtc_init(pScrn, drmmode, i);
    815 
    816     for (i = 0; i < drmmode->mode_res->count_connectors; i++)
    817         drmmode_output_init(pScrn, drmmode, i);
    818 
    819     /* workout clones */
    820     drmmode_clones_init(pScrn, drmmode);
    821     return TRUE;
    822 }
    823 
    824 #ifdef HAVE_UDEV
    825 static void
    826 drmmode_handle_uevents(int fd, void *closure)
    827 {
    828     drmmode_ptr drmmode = closure;
    829     ScrnInfoPtr scrn = drmmode->scrn;
    830     struct udev_device *dev;
    831 
    832     dev = udev_monitor_receive_device(drmmode->uevent_monitor);
    833     if (!dev)
    834         return;
    835 
    836     RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
    837     udev_device_unref(dev);
    838 }
    839 #endif
    840 
    841 void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
    842 {
    843 #ifdef HAVE_UDEV
    844     struct udev_monitor *mon;
    845     struct udev *u;
    846 
    847     u = udev_new();
    848     if (!u)
    849         return;
    850 
    851     mon = udev_monitor_new_from_netlink(u, "udev");
    852     if (!mon) {
    853         udev_unref(u);
    854         return;
    855     }
    856 
    857     if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") < 0 ||
    858             udev_monitor_enable_receiving(mon) < 0) {
    859         udev_monitor_unref(mon);
    860         udev_unref(u);
    861         return;
    862     }
    863 
    864     drmmode->uevent_handler = xf86AddGeneralHandler(udev_monitor_get_fd(mon),
    865                                                     drmmode_handle_uevents,
    866                                                     drmmode);
    867     drmmode->uevent_monitor = mon;
    868 #endif
    869 }
    870 
    871 void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
    872 {
    873 #ifdef HAVE_UDEV
    874     if (drmmode->uevent_handler) {
    875         struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
    876 
    877         xf86RemoveGeneralHandler(drmmode->uevent_handler);
    878 
    879         udev_monitor_unref(drmmode->uevent_monitor);
    880         udev_unref(u);
    881     }
    882 #endif
    883 }
    884