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