~ubuntu-branches/ubuntu/precise/xserver-xorg-video-openchrome-lts-trusty/precise-proposed

« back to all changes in this revision

Viewing changes to src/via_kms.c

  • Committer: Package Import Robot
  • Author(s): Maarten Lankhorst
  • Date: 2014-05-15 12:47:33 UTC
  • Revision ID: package-import@ubuntu.com-20140515124733-qw5cb5dqlvejqsy3
Tags: upstream-0.3.3
Import upstream version 0.3.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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@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
    xf86SetModeDefaultName(mode);
 
191
    drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
 
192
 
 
193
    if (drmmode->fb_id == 0) {
 
194
        ret = drmModeAddFB(drmmode->fd, pScrn->virtualX, pScrn->virtualY,
 
195
                            pScrn->depth, pScrn->bitsPerPixel,
 
196
                            drmmode->front_bo->pitch,
 
197
                            drmmode->front_bo->handle,
 
198
                            &drmmode->fb_id);
 
199
        if (ret < 0) {
 
200
            ErrorF("failed to add fb %d\n", ret);
 
201
            goto done;
 
202
        }
 
203
    }
 
204
 
 
205
    ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
 
206
                         drmmode->fb_id, x, y, output_ids, output_count, &kmode);
 
207
    if (ret) {
 
208
        xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, "failed to set mode: %s",
 
209
                   strerror(-ret));
 
210
        goto done;
 
211
    }
 
212
 
 
213
    if (crtc->scrn->pScreen)
 
214
        xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
 
215
 
 
216
    /* go through all the outputs and force DPMS them back on? */
 
217
    for (i = 0; i < xf86_config->num_output; i++) {
 
218
        xf86OutputPtr output = xf86_config->output[i];
 
219
 
 
220
        if (output->crtc != crtc)
 
221
            continue;
 
222
 
 
223
        output->funcs->dpms(output, DPMSModeOn);
 
224
    }
 
225
 
 
226
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0)
 
227
    crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
 
228
                           crtc->gamma_blue, crtc->gamma_size);
 
229
#endif
 
230
 
 
231
    if (pScrn->pScreen && drmmode->hwcursor)
 
232
        xf86_reload_cursors(pScrn->pScreen);
 
233
done:
 
234
    free(output_ids);
 
235
    return (ret < 0 ? FALSE : TRUE);
 
236
}
 
237
 
 
238
static void
 
239
drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
 
240
{
 
241
}
 
242
 
 
243
static void
 
244
drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
 
245
{
 
246
    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 
247
    drmmode_ptr drmmode = drmmode_crtc->drmmode;
 
248
 
 
249
    drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
 
250
}
 
251
 
 
252
static void
 
253
drmmode_hide_cursor (xf86CrtcPtr crtc)
 
254
{
 
255
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
 
256
    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 
257
    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
 
258
    drmmode_ptr drmmode = drmmode_crtc->drmmode;
 
259
 
 
260
    drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
 
261
                        cursor_info->MaxWidth, cursor_info->MaxHeight);
 
262
}
 
263
 
 
264
static void
 
265
drmmode_show_cursor (xf86CrtcPtr crtc)
 
266
{
 
267
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
 
268
    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 
269
    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
 
270
    uint32_t handle = drmmode_crtc->cursor_bo->handle;
 
271
    drmmode_ptr drmmode = drmmode_crtc->drmmode;
 
272
 
 
273
    drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle,
 
274
                        cursor_info->MaxWidth, cursor_info->MaxHeight);
 
275
}
 
276
 
 
277
static void
 
278
drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
 
279
{
 
280
    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
 
281
    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 
282
    xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
 
283
    uint32_t handle = drmmode_crtc->cursor_bo->handle, *ptr;
 
284
 
 
285
    /* cursor should be mapped already */
 
286
    ptr = drm_bo_map(crtc->scrn, drmmode_crtc->cursor_bo);
 
287
    memset(ptr, 0x00, drmmode_crtc->cursor_bo->size);
 
288
    memcpy(ptr, image, drmmode_crtc->cursor_bo->size);
 
289
    drm_bo_unmap(crtc->scrn, drmmode_crtc->cursor_bo);
 
290
 
 
291
    if (drmModeSetCursor(drmmode_crtc->drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
 
292
                            handle, cursor_info->MaxWidth, cursor_info->MaxHeight)) {
 
293
        drmmode_ptr drmmode = drmmode_crtc->drmmode;
 
294
 
 
295
        cursor_info->MaxWidth = cursor_info->MaxHeight = 0;
 
296
        drmmode->hwcursor = FALSE;
 
297
    }
 
298
}
 
299
 
 
300
static void
 
301
drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
 
302
                      uint16_t *blue, int size)
 
303
{
 
304
    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 
305
    drmmode_ptr drmmode = drmmode_crtc->drmmode;
 
306
 
 
307
    drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
 
308
                        size, red, green, blue);
 
309
}
 
310
 
 
311
static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
 
312
    .dpms                   = drmmode_crtc_dpms,
 
313
    .set_mode_major         = drmmode_set_mode_major,
 
314
    .set_cursor_colors      = drmmode_set_cursor_colors,
 
315
    .set_cursor_position    = drmmode_set_cursor_position,
 
316
    .show_cursor            = drmmode_show_cursor,
 
317
    .hide_cursor            = drmmode_hide_cursor,
 
318
    .load_cursor_argb       = drmmode_load_cursor_argb,
 
319
    .gamma_set              = drmmode_crtc_gamma_set,
 
320
    .destroy                = NULL,
 
321
};
 
322
 
 
323
static void
 
324
drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
 
325
{
 
326
    drmmode_crtc_private_ptr drmmode_crtc;
 
327
    xf86CrtcPtr crtc;
 
328
 
 
329
    crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
 
330
    if (crtc == NULL)
 
331
        return;
 
332
 
 
333
    drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
 
334
    drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]);
 
335
    drmmode_crtc->drmmode = drmmode;
 
336
    crtc->driver_private = drmmode_crtc;
 
337
}
 
338
 
 
339
/*
 
340
 * Handle KMS xf86Outputs
 
341
 */
 
342
static Bool
 
343
drmmode_property_ignore(drmModePropertyPtr prop)
 
344
{
 
345
    if (!prop)
 
346
        return TRUE;
 
347
 
 
348
    /* ignore blob prop */
 
349
    if (prop->flags & DRM_MODE_PROP_BLOB)
 
350
        return TRUE;
 
351
 
 
352
    /* ignore standard property */
 
353
    if (!strcmp(prop->name, "EDID") ||
 
354
        !strcmp(prop->name, "DPMS"))
 
355
        return TRUE;
 
356
 
 
357
    return FALSE;
 
358
}
 
359
 
 
360
static void
 
361
drmmode_output_dpms(xf86OutputPtr output, int mode)
 
362
{
 
363
        drmmode_output_private_ptr drmmode_output = output->driver_private;
 
364
        drmModeConnectorPtr koutput = drmmode_output->mode_output;
 
365
        drmmode_ptr drmmode = drmmode_output->drmmode;
 
366
 
 
367
        drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
 
368
                                    drmmode_output->dpms_enum_id, mode);
 
369
        return;
 
370
}
 
371
 
 
372
static void
 
373
drmmode_output_create_resources(xf86OutputPtr output)
 
374
{
 
375
    drmmode_output_private_ptr drmmode_output = output->driver_private;
 
376
    drmModeConnectorPtr mode_output = drmmode_output->mode_output;
 
377
    drmmode_ptr drmmode = drmmode_output->drmmode;
 
378
    drmModePropertyPtr drmmode_prop;
 
379
    int i, j, err;
 
380
 
 
381
    drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
 
382
    if (!drmmode_output->props)
 
383
        return;
 
384
 
 
385
    drmmode_output->num_props = 0;
 
386
    for (i = 0, j = 0; i < mode_output->count_props; i++) {
 
387
            drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
 
388
 
 
389
        if (drmmode_property_ignore(drmmode_prop)) {
 
390
                drmModeFreeProperty(drmmode_prop);
 
391
            continue;
 
392
        }
 
393
        drmmode_output->props[j].mode_prop = drmmode_prop;
 
394
        drmmode_output->props[j].value = mode_output->prop_values[i];
 
395
        drmmode_output->num_props++;
 
396
        j++;
 
397
    }
 
398
 
 
399
    for (i = 0; i < drmmode_output->num_props; i++) {
 
400
        drmmode_prop_ptr p = &drmmode_output->props[i];
 
401
        drmmode_prop = p->mode_prop;
 
402
 
 
403
        if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
 
404
            INT32 range[2];
 
405
            INT32 value = p->value;
 
406
 
 
407
            p->num_atoms = 1;
 
408
            p->atoms = calloc(p->num_atoms, sizeof(Atom));
 
409
            if (!p->atoms)
 
410
                continue;
 
411
            p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
 
412
            range[0] = drmmode_prop->values[0];
 
413
            range[1] = drmmode_prop->values[1];
 
414
            err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
 
415
                                            FALSE, TRUE,
 
416
                                            drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
 
417
                                            2, range);
 
418
            if (err != 0) {
 
419
                xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
 
420
                            "RRConfigureOutputProperty error, %d\n", err);
 
421
            }
 
422
            err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
 
423
                                        XA_INTEGER, 32, PropModeReplace, 1,
 
424
                                        &value, FALSE, TRUE);
 
425
            if (err != 0) {
 
426
                xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
 
427
                            "RRChangeOutputProperty error, %d\n", err);
 
428
            }
 
429
 
 
430
        } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
 
431
            p->num_atoms = drmmode_prop->count_enums + 1;
 
432
            p->atoms = calloc(p->num_atoms, sizeof(Atom));
 
433
            if (!p->atoms)
 
434
                continue;
 
435
 
 
436
            p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
 
437
            for (j = 1; j <= drmmode_prop->count_enums; j++) {
 
438
                struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
 
439
 
 
440
                p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
 
441
            }
 
442
            err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
 
443
                                            FALSE, FALSE,
 
444
                                            drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
 
445
                                            p->num_atoms - 1, (INT32 *)&p->atoms[1]);
 
446
            if (err != 0) {
 
447
                xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
 
448
                            "RRConfigureOutputProperty error, %d\n", err);
 
449
            }
 
450
 
 
451
            for (j = 0; j < drmmode_prop->count_enums; j++)
 
452
                if (drmmode_prop->enums[j].value == p->value)
 
453
                    break;
 
454
 
 
455
            /* there's always a matching value */
 
456
            err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
 
457
                                        XA_ATOM, 32, PropModeReplace, 1,
 
458
                                        &p->atoms[j+1], FALSE, TRUE);
 
459
            if (err != 0) {
 
460
                xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
 
461
                            "RRChangeOutputProperty error, %d\n", err);
 
462
            }
 
463
        }
 
464
    }
 
465
}
 
466
 
 
467
static Bool
 
468
drmmode_output_set_property(xf86OutputPtr output, Atom property,
 
469
                            RRPropertyValuePtr value)
 
470
{
 
471
    drmmode_output_private_ptr drmmode_output = output->driver_private;
 
472
    drmmode_ptr drmmode = drmmode_output->drmmode;
 
473
    int i;
 
474
 
 
475
    for (i = 0; i < drmmode_output->num_props; i++) {
 
476
        drmmode_prop_ptr p = &drmmode_output->props[i];
 
477
 
 
478
        if (p->atoms[0] != property)
 
479
            continue;
 
480
 
 
481
        if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
 
482
            uint32_t val;
 
483
 
 
484
            if (value->type != XA_INTEGER || value->format != 32 ||
 
485
                value->size != 1)
 
486
                return FALSE;
 
487
            val = *(uint32_t *)value->data;
 
488
 
 
489
            drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
 
490
                                        p->mode_prop->prop_id, (uint64_t)val);
 
491
            return TRUE;
 
492
        } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
 
493
            const char *name;
 
494
            Atom atom;
 
495
            int j;
 
496
 
 
497
            if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
 
498
                return FALSE;
 
499
            memcpy(&atom, value->data, 4);
 
500
            name = NameForAtom(atom);
 
501
 
 
502
            /* search for matching name string, then set its value down */
 
503
            for (j = 0; j < p->mode_prop->count_enums; j++) {
 
504
                if (!strcmp(p->mode_prop->enums[j].name, name)) {
 
505
                    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
 
506
                    p->mode_prop->prop_id, p->mode_prop->enums[j].value);
 
507
                    return TRUE;
 
508
                }
 
509
            }
 
510
        }
 
511
    }
 
512
    return TRUE;
 
513
}
 
514
 
 
515
static Bool
 
516
drmmode_output_get_property(xf86OutputPtr output, Atom property)
 
517
{
 
518
    return TRUE;
 
519
}
 
520
 
 
521
static xf86OutputStatus
 
522
drmmode_output_detect(xf86OutputPtr output)
 
523
{
 
524
    /* go to the hw and retrieve a new output struct */
 
525
    drmmode_output_private_ptr drmmode_output = output->driver_private;
 
526
    drmmode_ptr drmmode = drmmode_output->drmmode;
 
527
    xf86OutputStatus status;
 
528
 
 
529
    drmModeFreeConnector(drmmode_output->mode_output);
 
530
    drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
 
531
 
 
532
    switch (drmmode_output->mode_output->connection) {
 
533
    case DRM_MODE_CONNECTED:
 
534
        status = XF86OutputStatusConnected;
 
535
        break;
 
536
    case DRM_MODE_DISCONNECTED:
 
537
        status = XF86OutputStatusDisconnected;
 
538
        break;
 
539
    default:
 
540
    case DRM_MODE_UNKNOWNCONNECTION:
 
541
        status = XF86OutputStatusUnknown;
 
542
        break;
 
543
    }
 
544
    return status;
 
545
}
 
546
 
 
547
static Bool
 
548
drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
 
549
{
 
550
    return MODE_OK;
 
551
}
 
552
 
 
553
static DisplayModePtr
 
554
drmmode_output_get_modes(xf86OutputPtr output)
 
555
{
 
556
    drmmode_output_private_ptr drmmode_output = output->driver_private;
 
557
    drmModeConnectorPtr koutput = drmmode_output->mode_output;
 
558
    drmmode_ptr drmmode = drmmode_output->drmmode;
 
559
    DisplayModePtr Modes = NULL, Mode;
 
560
    drmModePropertyPtr props;
 
561
    xf86MonPtr mon = NULL;
 
562
    int i;
 
563
 
 
564
    /* look for an EDID property */
 
565
    for (i = 0; i < koutput->count_props; i++) {
 
566
        props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
 
567
        if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
 
568
            if (!strcmp(props->name, "EDID")) {
 
569
                if (drmmode_output->edid_blob)
 
570
                    drmModeFreePropertyBlob(drmmode_output->edid_blob);
 
571
                drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
 
572
            }
 
573
            drmModeFreeProperty(props);
 
574
        }
 
575
    }
 
576
 
 
577
    if (drmmode_output->edid_blob) {
 
578
        mon = xf86InterpretEDID(output->scrn->scrnIndex,
 
579
                                drmmode_output->edid_blob->data);
 
580
        if (mon && drmmode_output->edid_blob->length > 128)
 
581
            mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
 
582
    }
 
583
    xf86OutputSetEDID(output, mon);
 
584
 
 
585
    /* modes should already be available */
 
586
    for (i = 0; i < koutput->count_modes; i++) {
 
587
        Mode = xnfalloc(sizeof(DisplayModeRec));
 
588
 
 
589
        drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
 
590
        Modes = xf86ModesAdd(Modes, Mode);
 
591
 
 
592
    }
 
593
    return Modes;
 
594
}
 
595
 
 
596
static void
 
597
drmmode_output_destroy(xf86OutputPtr output)
 
598
{
 
599
    drmmode_output_private_ptr drmmode_output = output->driver_private;
 
600
    int i;
 
601
 
 
602
    if (drmmode_output->edid_blob)
 
603
        drmModeFreePropertyBlob(drmmode_output->edid_blob);
 
604
 
 
605
    for (i = 0; i < drmmode_output->num_props; i++) {
 
606
        drmModeFreeProperty(drmmode_output->props[i].mode_prop);
 
607
        free(drmmode_output->props[i].atoms);
 
608
    }
 
609
 
 
610
    for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
 
611
        drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
 
612
        free(drmmode_output->mode_encoders);
 
613
    }
 
614
    free(drmmode_output->props);
 
615
    drmModeFreeConnector(drmmode_output->mode_output);
 
616
    free(drmmode_output);
 
617
    output->driver_private = NULL;
 
618
}
 
619
 
 
620
static const xf86OutputFuncsRec drmmode_output_funcs = {
 
621
    .dpms               = drmmode_output_dpms,
 
622
    .create_resources   = drmmode_output_create_resources,
 
623
#ifdef RANDR_12_INTERFACE
 
624
    .set_property       = drmmode_output_set_property,
 
625
    .get_property       = drmmode_output_get_property,
 
626
#endif
 
627
    .detect             = drmmode_output_detect,
 
628
    .mode_valid         = drmmode_output_mode_valid,
 
629
    .get_modes          = drmmode_output_get_modes,
 
630
    .destroy            = drmmode_output_destroy
 
631
};
 
632
 
 
633
static int subpixel_conv_table[7] = {
 
634
    0,
 
635
    SubPixelUnknown,
 
636
    SubPixelHorizontalRGB,
 
637
    SubPixelHorizontalBGR,
 
638
    SubPixelVerticalRGB,
 
639
    SubPixelVerticalBGR,
 
640
    SubPixelNone
 
641
};
 
642
 
 
643
const char *output_names[] = {
 
644
    "None",
 
645
    "VGA",
 
646
    "DVI",
 
647
    "DVI",
 
648
    "DVI",
 
649
    "Composite",
 
650
    "S-video",
 
651
    "LVDS",
 
652
    "CTV",
 
653
    "DIN",
 
654
    "DisplayPort",
 
655
    "HDMI",
 
656
    "HDMI",
 
657
    "TV",
 
658
    "eDP"
 
659
};
 
660
 
 
661
static void
 
662
drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
 
663
{
 
664
    xf86OutputPtr output;
 
665
    drmModeConnectorPtr koutput;
 
666
    drmModeEncoderPtr *kencoders = NULL;
 
667
    drmmode_output_private_ptr drmmode_output;
 
668
    drmModePropertyPtr props;
 
669
    char name[32];
 
670
    int i;
 
671
 
 
672
    koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
 
673
    if (!koutput)
 
674
        return;
 
675
 
 
676
    kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
 
677
    if (!kencoders) {
 
678
        goto out_free_encoders;
 
679
    }
 
680
 
 
681
    for (i = 0; i < koutput->count_encoders; i++) {
 
682
        kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
 
683
        if (!kencoders[i]) {
 
684
            goto out_free_encoders;
 
685
        }
 
686
    }
 
687
 
 
688
    /* need to do smart conversion here for compat with non-kms ATI driver */
 
689
    snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
 
690
 
 
691
    output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
 
692
    if (!output) {
 
693
        goto out_free_encoders;
 
694
    }
 
695
 
 
696
    drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
 
697
    if (!drmmode_output) {
 
698
        xf86OutputDestroy(output);
 
699
        goto out_free_encoders;
 
700
    }
 
701
 
 
702
    drmmode_output->output_id = drmmode->mode_res->connectors[num];
 
703
    drmmode_output->mode_output = koutput;
 
704
    drmmode_output->mode_encoders = kencoders;
 
705
    drmmode_output->drmmode = drmmode;
 
706
    output->mm_width = koutput->mmWidth;
 
707
    output->mm_height = koutput->mmHeight;
 
708
 
 
709
    output->subpixel_order = subpixel_conv_table[koutput->subpixel];
 
710
    output->interlaceAllowed = TRUE;
 
711
    output->doubleScanAllowed = TRUE;
 
712
    output->driver_private = drmmode_output;
 
713
 
 
714
    output->possible_crtcs = 0x7f;
 
715
    for (i = 0; i < koutput->count_encoders; i++)
 
716
        output->possible_crtcs &= kencoders[i]->possible_crtcs;
 
717
 
 
718
    /* work out the possible clones later */
 
719
    output->possible_clones = 0;
 
720
 
 
721
    for (i = 0; i < koutput->count_props; i++) {
 
722
        props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
 
723
        if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
 
724
            if (!strcmp(props->name, "DPMS")) {
 
725
                drmmode_output->dpms_enum_id = koutput->props[i];
 
726
                drmModeFreeProperty(props);
 
727
                break;
 
728
            }
 
729
            drmModeFreeProperty(props);
 
730
        }
 
731
    }
 
732
 
 
733
    return;
 
734
out_free_encoders:
 
735
    if (kencoders){
 
736
        for (i = 0; i < koutput->count_encoders; i++)
 
737
            drmModeFreeEncoder(kencoders[i]);
 
738
        free(kencoders);
 
739
    }
 
740
    drmModeFreeConnector(koutput);
 
741
}
 
742
 
 
743
uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
 
744
{
 
745
    drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout;
 
746
    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
 
747
    xf86OutputPtr clone_output;
 
748
    int index_mask = 0, i;
 
749
 
 
750
    if (drmmode_output->enc_clone_mask == 0)
 
751
        return index_mask;
 
752
 
 
753
    for (i = 0; i < xf86_config->num_output; i++) {
 
754
        clone_output = xf86_config->output[i];
 
755
        clone_drmout = clone_output->driver_private;
 
756
        if (output == clone_output)
 
757
            continue;
 
758
        if (clone_drmout->enc_mask == 0)
 
759
            continue;
 
760
        if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
 
761
            index_mask |= (1 << i);
 
762
    }
 
763
    return index_mask;
 
764
}
 
765
 
 
766
static void
 
767
drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
 
768
{
 
769
    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
 
770
    int i, j;
 
771
 
 
772
    for (i = 0; i < xf86_config->num_output; i++) {
 
773
        xf86OutputPtr output = xf86_config->output[i];
 
774
        drmmode_output_private_ptr drmmode_output;
 
775
 
 
776
        drmmode_output = output->driver_private;
 
777
        drmmode_output->enc_clone_mask = 0xff;
 
778
        /* and all the possible encoder clones for this output together */
 
779
        for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) {
 
780
            int k;
 
781
 
 
782
            for (k = 0; k < drmmode->mode_res->count_encoders; k++) {
 
783
                if (drmmode->mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id)
 
784
                    drmmode_output->enc_mask |= (1 << k);
 
785
            }
 
786
 
 
787
            drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones;
 
788
        }
 
789
    }
 
790
 
 
791
    for (i = 0; i < xf86_config->num_output; i++) {
 
792
        xf86OutputPtr output = xf86_config->output[i];
 
793
        output->possible_clones = find_clones(scrn, output);
 
794
    }
 
795
}
 
796
 
 
797
Bool KMSCrtcInit(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
 
798
{
 
799
    int i;
 
800
 
 
801
    DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "KMSCrtcInit\n"));
 
802
 
 
803
    drmmode->scrn = pScrn;
 
804
    drmmode->mode_res = drmModeGetResources(drmmode->fd);
 
805
    if (!drmmode->mode_res)
 
806
        return FALSE;
 
807
 
 
808
    xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height);
 
809
    for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
 
810
        if (!xf86IsEntityShared(pScrn->entityList[0]) || pScrn->confScreen->device->screen == i)
 
811
            drmmode_crtc_init(pScrn, drmmode, i);
 
812
 
 
813
    for (i = 0; i < drmmode->mode_res->count_connectors; i++)
 
814
        drmmode_output_init(pScrn, drmmode, i);
 
815
 
 
816
    /* workout clones */
 
817
    drmmode_clones_init(pScrn, drmmode);
 
818
    return TRUE;
 
819
}
 
820
 
 
821
#ifdef HAVE_UDEV
 
822
static void
 
823
drmmode_handle_uevents(int fd, void *closure)
 
824
{
 
825
    drmmode_ptr drmmode = closure;
 
826
    ScrnInfoPtr scrn = drmmode->scrn;
 
827
    struct udev_device *dev;
 
828
 
 
829
    dev = udev_monitor_receive_device(drmmode->uevent_monitor);
 
830
    if (!dev)
 
831
        return;
 
832
 
 
833
    RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
 
834
    udev_device_unref(dev);
 
835
}
 
836
#endif
 
837
 
 
838
void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
 
839
{
 
840
#ifdef HAVE_UDEV
 
841
    struct udev_monitor *mon;
 
842
    struct udev *u;
 
843
 
 
844
    u = udev_new();
 
845
    if (!u)
 
846
        return;
 
847
 
 
848
    mon = udev_monitor_new_from_netlink(u, "udev");
 
849
    if (!mon) {
 
850
        udev_unref(u);
 
851
        return;
 
852
    }
 
853
 
 
854
    if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") < 0 ||
 
855
            udev_monitor_enable_receiving(mon) < 0) {
 
856
        udev_monitor_unref(mon);
 
857
        udev_unref(u);
 
858
        return;
 
859
    }
 
860
 
 
861
    drmmode->uevent_handler = xf86AddGeneralHandler(udev_monitor_get_fd(mon),
 
862
                                                    drmmode_handle_uevents,
 
863
                                                    drmmode);
 
864
    drmmode->uevent_monitor = mon;
 
865
#endif
 
866
}
 
867
 
 
868
void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
 
869
{
 
870
#ifdef HAVE_UDEV
 
871
    if (drmmode->uevent_handler) {
 
872
        struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
 
873
 
 
874
        xf86RemoveGeneralHandler(drmmode->uevent_handler);
 
875
 
 
876
        udev_monitor_unref(drmmode->uevent_monitor);
 
877
        udev_unref(u);
 
878
    }
 
879
#endif
 
880
}