blob: a6483c32f9d3fa0c44193ce5cc6ee14ca2830e31 [file] [log] [blame]
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "drm_utils.h"
static int fd = -1;
static drmModeResPtr res = NULL;
int
drm_init(void)
{
int ret;
ret = drmOpen("i915", NULL);
if (ret < 0)
return ret;
fd = ret;
/* give up drm master in case we are first */
drmDropMaster(fd);
res = drmModeGetResources(fd);
if (!res) {
drmClose(fd);
fd = -1;
return -1;
}
return 0;
}
void
drm_done(void)
{
if (res) {
drmModeFreeResources(res);
res = NULL;
}
if (fd >= 0) {
drmClose(fd);
fd = -1;
}
}
static drmModeConnectorPtr
find_connector(drmModeCrtcPtr crtc)
{
int c;
for (c = 0; c < res->count_connectors; c++) {
drmModeConnectorPtr connector;
drmModeEncoderPtr encoder;
connector = drmModeGetConnector(fd, res->connectors[c]);
if (!connector)
continue;
encoder = drmModeGetEncoder(fd, connector->encoder_id);
if (!encoder) {
drmModeFreeConnector(connector);
continue;
}
if (encoder->crtc_id == crtc->crtc_id) {
/* got it */
drmModeFreeEncoder(encoder);
return connector;
}
drmModeFreeEncoder(encoder);
drmModeFreeConnector(connector);
}
return NULL;
}
static int get_dpms(drmModeConnectorPtr connector, int *dpms)
{
int p;
if (!connector) {
*dpms = DRM_MODE_DPMS_OFF;
return 0;
}
for (p = 0; p < connector->count_props; p++) {
drmModePropertyPtr prop;
prop = drmModeGetProperty(fd, connector->props[p]);
if (prop) {
if (!strcmp(prop->name, "DPMS")) {
*dpms = (int)connector->prop_values[p];
drmModeFreeProperty(prop);
return 0;
}
drmModeFreeProperty(prop);
}
}
/* no DPMS property, assume connector is on */
*dpms = DRM_MODE_DPMS_ON;
return 0;
}
int
drm_get_mode(drmModeModeInfoPtr mode, int *dpms)
{
int c;
int found = 0;
if (fd < 0)
return -ENODEV;
/* find a crtc with a valid mode and return the info */
for (c = 0; c < res->count_crtcs && !found; c++) {
drmModeCrtcPtr crtc;
crtc = drmModeGetCrtc(fd, res->crtcs[c]);
if (crtc) {
if (crtc->buffer_id && crtc->mode_valid) {
drmModeConnectorPtr connector;
*mode = crtc->mode;
found = 1;
connector = find_connector(crtc);
get_dpms(connector, dpms);
if (connector) {
drmModeFreeConnector(connector);
}
}
drmModeFreeCrtc(crtc);
}
}
if (!found) {
mode->htotal = mode->vtotal = 0;
*dpms = DRM_MODE_DPMS_OFF;
}
return 0;
}
static char modechar(int flags, int pos, int neg) {
return (flags & pos) ? '+' : ((flags & neg) ? '-' : '?');
}
void
drm_show_mode(drmModeModeInfoPtr mode)
{
printf("Mode %s\n", mode->name);
printf("%dx%d, dot clock %ld KHz %cHsync %cVsync\n",
mode->hdisplay, mode->vdisplay, mode->clock,
modechar(mode->flags, DRM_MODE_FLAG_PHSYNC, DRM_MODE_FLAG_NHSYNC),
modechar(mode->flags, DRM_MODE_FLAG_PVSYNC, DRM_MODE_FLAG_NVSYNC));
printf("H: start %d, end %d, skew %d, total %d\n",
mode->hsync_start, mode->hsync_end, mode->hskew, mode->htotal);
printf("V: start %d, end %d, total %d\n",
mode->vsync_start, mode->vsync_end, mode->vtotal);
}