2014-03-06 01:43:48 -08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "ecore_drm_private.h"
|
2015-03-04 11:53:06 -08:00
|
|
|
#include <ctype.h>
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-03-04 11:53:06 -08:00
|
|
|
#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
|
|
|
|
#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
|
|
|
|
#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
|
|
|
|
#define EDID_OFFSET_DATA_BLOCKS 0x36
|
|
|
|
#define EDID_OFFSET_LAST_BLOCK 0x6c
|
|
|
|
#define EDID_OFFSET_PNPID 0x08
|
|
|
|
#define EDID_OFFSET_SERIAL 0x0c
|
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
static const char *conn_types[] =
|
|
|
|
{
|
2015-03-24 12:34:04 -07:00
|
|
|
"None", "VGA", "DVI-I", "DVI-D", "DVI-A",
|
|
|
|
"Composite", "S-Video", "LVDS", "Component", "DIN",
|
2015-04-07 08:22:12 -07:00
|
|
|
"DisplayPort", "HDMI-A", "HDMI-B", "TV", "eDP", "Virtual",
|
|
|
|
"DSI",
|
2014-03-06 01:43:48 -08:00
|
|
|
};
|
|
|
|
|
2015-02-19 11:47:34 -08:00
|
|
|
EAPI int ECORE_DRM_EVENT_OUTPUT = 0;
|
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
static void
|
|
|
|
_ecore_drm_output_event_free(void *data EINA_UNUSED, void *event)
|
|
|
|
{
|
|
|
|
Ecore_Drm_Event_Output *e = event;
|
|
|
|
|
|
|
|
eina_stringshare_del(e->make);
|
|
|
|
eina_stringshare_del(e->model);
|
|
|
|
free(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_ecore_drm_output_event_send(const Ecore_Drm_Output *output, Eina_Bool plug)
|
|
|
|
{
|
|
|
|
Ecore_Drm_Event_Output *e;
|
|
|
|
|
|
|
|
if (!(e = calloc(1, sizeof(Ecore_Drm_Event_Output)))) return;
|
|
|
|
e->plug = plug;
|
|
|
|
e->id = output->crtc_id;
|
|
|
|
e->w = output->current_mode->width;
|
|
|
|
e->h = output->current_mode->height;
|
|
|
|
e->x = output->x;
|
|
|
|
e->y = output->y;
|
|
|
|
e->phys_width = output->phys_width;
|
|
|
|
e->phys_height = output->phys_height;
|
|
|
|
e->refresh = output->current_mode->refresh;
|
|
|
|
e->subpixel_order = output->subpixel;
|
|
|
|
e->make = eina_stringshare_ref(output->make);
|
|
|
|
e->model = eina_stringshare_ref(output->model);
|
|
|
|
e->transform = 0;
|
|
|
|
ecore_event_add(ECORE_DRM_EVENT_OUTPUT, e,
|
|
|
|
_ecore_drm_output_event_free, NULL);
|
|
|
|
}
|
|
|
|
|
2015-04-07 08:41:21 -07:00
|
|
|
static drmModePropertyPtr
|
|
|
|
_ecore_drm_output_property_get(int fd, drmModeConnectorPtr conn, const char *name)
|
|
|
|
{
|
|
|
|
drmModePropertyPtr prop;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for (; i < conn->count_props; i++)
|
|
|
|
{
|
|
|
|
if (!(prop = drmModeGetProperty(fd, conn->props[i])))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!strcmp(prop->name, name)) return prop;
|
|
|
|
|
|
|
|
drmModeFreeProperty(prop);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-03-04 11:53:06 -08:00
|
|
|
static void
|
|
|
|
_ecore_drm_output_edid_parse_string(const uint8_t *data, char text[])
|
|
|
|
{
|
|
|
|
int i = 0, rep = 0;
|
|
|
|
|
|
|
|
strncpy(text, (const char *)data, 12);
|
|
|
|
|
|
|
|
for (; text[i] != '\0'; i++)
|
|
|
|
{
|
|
|
|
if ((text[i] == '\n') || (text[i] == '\r'))
|
|
|
|
{
|
|
|
|
text[i] = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; text[i] != '\0'; i++)
|
|
|
|
{
|
|
|
|
if (!isprint(text[i]))
|
|
|
|
{
|
|
|
|
text[i] = '-';
|
|
|
|
rep++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-12 08:51:01 -07:00
|
|
|
if (rep > 4) text[0] = '\0';
|
2015-03-04 11:53:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
_ecore_drm_output_edid_parse(Ecore_Drm_Output *output, const uint8_t *data, size_t len)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
uint32_t serial;
|
|
|
|
|
|
|
|
if (len < 128) return -1;
|
|
|
|
if ((data[0] != 0x00) || (data[1] != 0xff)) return -1;
|
|
|
|
|
|
|
|
output->edid.pnp[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
|
|
|
|
output->edid.pnp[1] =
|
|
|
|
'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) +
|
|
|
|
((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
|
|
|
|
output->edid.pnp[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
|
|
|
|
output->edid.pnp[3] = '\0';
|
|
|
|
|
|
|
|
serial = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
|
|
|
|
serial += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
|
|
|
|
serial += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
|
|
|
|
serial += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
|
|
|
|
if (serial > 0)
|
|
|
|
sprintf(output->edid.serial, "%lu", (unsigned long)serial);
|
|
|
|
|
|
|
|
for (i = EDID_OFFSET_DATA_BLOCKS; i <= EDID_OFFSET_LAST_BLOCK; i += 18)
|
|
|
|
{
|
|
|
|
if (data[i] != 0) continue;
|
|
|
|
if (data[i + 2] != 0) continue;
|
|
|
|
|
|
|
|
if (data[i + 3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME)
|
2015-04-07 08:24:17 -07:00
|
|
|
_ecore_drm_output_edid_parse_string(&data[i + 5], output->edid.monitor);
|
2015-03-04 11:53:06 -08:00
|
|
|
else if (data[i + 3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER)
|
2015-04-07 08:24:17 -07:00
|
|
|
_ecore_drm_output_edid_parse_string(&data[i + 5], output->edid.serial);
|
2015-03-04 11:53:06 -08:00
|
|
|
else if (data[i + 3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING)
|
2015-04-07 08:24:17 -07:00
|
|
|
_ecore_drm_output_edid_parse_string(&data[i + 5], output->edid.eisa);
|
2015-03-04 11:53:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_ecore_drm_output_edid_find(Ecore_Drm_Output *output, drmModeConnector *conn)
|
|
|
|
{
|
|
|
|
drmModePropertyBlobPtr blob = NULL;
|
|
|
|
drmModePropertyPtr prop;
|
|
|
|
int i = 0, ret = 0;
|
|
|
|
|
|
|
|
for (; i < conn->count_props && !blob; i++)
|
|
|
|
{
|
|
|
|
if (!(prop = drmModeGetProperty(output->dev->drm.fd, conn->props[i])))
|
|
|
|
continue;
|
|
|
|
if ((prop->flags & DRM_MODE_PROP_BLOB) &&
|
|
|
|
(!strcmp(prop->name, "EDID")))
|
|
|
|
{
|
|
|
|
blob = drmModeGetPropertyBlob(output->dev->drm.fd,
|
|
|
|
conn->prop_values[i]);
|
|
|
|
}
|
|
|
|
drmModeFreeProperty(prop);
|
2015-05-04 12:03:47 -07:00
|
|
|
if (blob) break;
|
2015-03-04 11:53:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!blob) return;
|
|
|
|
|
2015-05-12 08:56:52 -07:00
|
|
|
output->edid_blob = eina_memdup(blob->data, blob->length, 1);
|
2015-05-04 12:03:47 -07:00
|
|
|
|
2015-03-04 11:53:06 -08:00
|
|
|
ret = _ecore_drm_output_edid_parse(output, blob->data, blob->length);
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
if (output->edid.pnp[0] != '\0')
|
|
|
|
eina_stringshare_replace(&output->make, output->edid.pnp);
|
|
|
|
if (output->edid.monitor[0] != '\0')
|
|
|
|
eina_stringshare_replace(&output->model, output->edid.monitor);
|
|
|
|
/* if (output->edid.serial[0] != '\0') */
|
|
|
|
/* eina_stringshare_replace(&output->serial, output->edid.serial); */
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreePropertyBlob(blob);
|
|
|
|
}
|
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
static void
|
|
|
|
_ecore_drm_output_software_render(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
if (!output) return;
|
|
|
|
if (!output->current_mode) return;
|
|
|
|
}
|
|
|
|
|
2014-07-01 06:01:38 -07:00
|
|
|
static int
|
2014-03-06 01:43:48 -08:00
|
|
|
_ecore_drm_output_crtc_find(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnector *conn)
|
|
|
|
{
|
|
|
|
drmModeEncoder *enc;
|
|
|
|
unsigned int p;
|
2014-07-01 06:01:38 -07:00
|
|
|
int i, j;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2014-07-01 06:01:38 -07:00
|
|
|
/* We did not find an existing encoder + crtc combination. Loop through all of them until we
|
|
|
|
* find the first working combination */
|
2014-03-06 01:43:48 -08:00
|
|
|
for (j = 0; j < conn->count_encoders; j++)
|
|
|
|
{
|
|
|
|
/* get the encoder on this connector */
|
|
|
|
if (!(enc = drmModeGetEncoder(dev->drm.fd, conn->encoders[j])))
|
|
|
|
{
|
2014-07-01 06:01:38 -07:00
|
|
|
WRN("Failed to get encoder: %m");
|
|
|
|
continue;
|
2014-03-06 01:43:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
p = enc->possible_crtcs;
|
|
|
|
drmModeFreeEncoder(enc);
|
|
|
|
|
2014-07-01 06:01:38 -07:00
|
|
|
/* Walk over all CRTCs */
|
2014-03-06 01:43:48 -08:00
|
|
|
for (i = 0; i < res->count_crtcs; i++)
|
|
|
|
{
|
2014-07-01 06:01:38 -07:00
|
|
|
/* Does the CRTC match the list of possible CRTCs from the encoder? */
|
|
|
|
if ((p & (1 << i)) &&
|
2014-03-06 01:43:48 -08:00
|
|
|
(!(dev->crtc_allocator & (1 << res->crtcs[i]))))
|
|
|
|
{
|
2015-03-11 14:09:48 -07:00
|
|
|
return i;
|
2014-03-06 01:43:48 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Ecore_Drm_Output_Mode *
|
|
|
|
_ecore_drm_output_mode_add(Ecore_Drm_Output *output, drmModeModeInfo *info)
|
|
|
|
{
|
|
|
|
Ecore_Drm_Output_Mode *mode;
|
|
|
|
uint64_t refresh;
|
|
|
|
|
|
|
|
/* try to allocate space for mode */
|
|
|
|
if (!(mode = malloc(sizeof(Ecore_Drm_Output_Mode))))
|
|
|
|
{
|
|
|
|
ERR("Could not allocate space for mode");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
mode->flags = 0;
|
|
|
|
mode->width = info->hdisplay;
|
|
|
|
mode->height = info->vdisplay;
|
|
|
|
|
|
|
|
refresh = (info->clock * 1000000LL / info->htotal + info->vtotal / 2) / info->vtotal;
|
|
|
|
if (info->flags & DRM_MODE_FLAG_INTERLACE)
|
|
|
|
refresh *= 2;
|
|
|
|
if (info->flags & DRM_MODE_FLAG_DBLSCAN)
|
|
|
|
refresh /= 2;
|
|
|
|
if (info->vscan > 1)
|
|
|
|
refresh /= info->vscan;
|
|
|
|
|
|
|
|
mode->refresh = refresh;
|
|
|
|
mode->info = *info;
|
|
|
|
|
2015-04-07 09:26:19 -07:00
|
|
|
if (info->type & DRM_MODE_TYPE_PREFERRED)
|
|
|
|
mode->flags |= DRM_MODE_TYPE_PREFERRED;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
|
|
|
output->modes = eina_list_append(output->modes, mode);
|
|
|
|
|
|
|
|
return mode;
|
|
|
|
}
|
|
|
|
|
2014-11-25 00:01:36 -08:00
|
|
|
/* XXX: this code is currently unused comment out until needed
|
2014-09-24 06:58:57 -07:00
|
|
|
static double
|
|
|
|
_ecore_drm_output_brightness_get(Ecore_Drm_Backlight *backlight)
|
|
|
|
{
|
|
|
|
const char *brightness = NULL;
|
|
|
|
double ret;
|
|
|
|
|
2014-09-29 05:52:30 -07:00
|
|
|
if (!(backlight) || !(backlight->device))
|
|
|
|
return 0;
|
|
|
|
|
2014-09-24 06:58:57 -07:00
|
|
|
brightness = eeze_udev_syspath_get_sysattr(backlight->device, "brightness");
|
|
|
|
if (!brightness) return 0;
|
|
|
|
|
|
|
|
ret = strtod(brightness, NULL);
|
2014-12-10 07:04:22 -08:00
|
|
|
if (ret < 0) ret = 0;
|
2014-09-24 06:58:57 -07:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static double
|
|
|
|
_ecore_drm_output_actual_brightness_get(Ecore_Drm_Backlight *backlight)
|
|
|
|
{
|
|
|
|
const char *brightness = NULL;
|
|
|
|
double ret;
|
|
|
|
|
2014-09-29 05:52:30 -07:00
|
|
|
if (!(backlight) || !(backlight->device))
|
|
|
|
return 0;
|
|
|
|
|
2014-09-24 06:58:57 -07:00
|
|
|
brightness = eeze_udev_syspath_get_sysattr(backlight->device, "actual_brightness");
|
|
|
|
if (!brightness) return 0;
|
|
|
|
|
|
|
|
ret = strtod(brightness, NULL);
|
2014-12-10 07:04:22 -08:00
|
|
|
if (ret < 0) ret = 0;
|
2014-09-24 06:58:57 -07:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static double
|
|
|
|
_ecore_drm_output_max_brightness_get(Ecore_Drm_Backlight *backlight)
|
|
|
|
{
|
|
|
|
const char *brightness = NULL;
|
|
|
|
double ret;
|
|
|
|
|
2014-09-29 05:52:30 -07:00
|
|
|
if (!(backlight) || !(backlight->device))
|
|
|
|
return 0;
|
|
|
|
|
2014-09-24 06:58:57 -07:00
|
|
|
brightness = eeze_udev_syspath_get_sysattr(backlight->device, "max_brightness");
|
|
|
|
if (!brightness) return 0;
|
|
|
|
|
|
|
|
ret = strtod(brightness, NULL);
|
2014-12-10 07:04:22 -08:00
|
|
|
if (ret < 0) ret = 0;
|
2014-09-24 06:58:57 -07:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-09-29 05:52:30 -07:00
|
|
|
static double
|
|
|
|
_ecore_drm_output_brightness_set(Ecore_Drm_Backlight *backlight, double brightness_val)
|
|
|
|
{
|
|
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
|
|
|
|
if (!(backlight) || !(backlight->device))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = eeze_udev_syspath_set_sysattr(backlight->device, "brightness", brightness_val);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2014-11-25 00:01:36 -08:00
|
|
|
*/
|
2014-09-29 05:52:30 -07:00
|
|
|
|
2014-09-23 05:28:08 -07:00
|
|
|
static Ecore_Drm_Backlight *
|
2015-04-23 10:11:22 -07:00
|
|
|
_ecore_drm_output_backlight_init(Ecore_Drm_Output *output, uint32_t conn_type)
|
2014-09-23 05:28:08 -07:00
|
|
|
{
|
|
|
|
Ecore_Drm_Backlight *backlight = NULL;
|
|
|
|
Ecore_Drm_Backlight_Type type = 0;
|
2014-09-23 12:45:53 -07:00
|
|
|
Eina_List *devs, *l;
|
|
|
|
Eina_Bool found = EINA_FALSE;
|
2014-09-24 06:58:57 -07:00
|
|
|
const char *device, *devtype;
|
2014-09-23 12:45:53 -07:00
|
|
|
|
2015-04-23 10:17:25 -07:00
|
|
|
if (!(devs = eeze_udev_find_by_filter("backlight", NULL, output->dev->drm.path)))
|
|
|
|
devs = eeze_udev_find_by_filter("leds", NULL, output->dev->drm.path);
|
2014-09-23 05:28:08 -07:00
|
|
|
|
2014-09-23 12:45:53 -07:00
|
|
|
if (!devs) return NULL;
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(devs, l, device)
|
2014-09-23 05:28:08 -07:00
|
|
|
{
|
2014-09-23 12:45:53 -07:00
|
|
|
if (!(devtype = eeze_udev_syspath_get_sysattr(device, "type")))
|
|
|
|
continue;
|
2014-09-23 05:28:08 -07:00
|
|
|
|
2014-09-23 12:45:53 -07:00
|
|
|
if (!strcmp(devtype, "raw"))
|
2014-09-23 05:28:08 -07:00
|
|
|
type = ECORE_DRM_BACKLIGHT_RAW;
|
2014-09-23 12:45:53 -07:00
|
|
|
else if (!strcmp(devtype, "platform"))
|
2014-09-23 05:28:08 -07:00
|
|
|
type = ECORE_DRM_BACKLIGHT_PLATFORM;
|
2014-09-23 12:45:53 -07:00
|
|
|
else if (!strcmp(devtype, "firmware"))
|
2014-09-23 05:28:08 -07:00
|
|
|
type = ECORE_DRM_BACKLIGHT_FIRMWARE;
|
|
|
|
|
2015-04-23 10:21:32 -07:00
|
|
|
if ((conn_type == DRM_MODE_CONNECTOR_LVDS) ||
|
|
|
|
(conn_type == DRM_MODE_CONNECTOR_eDP) ||
|
|
|
|
(type == ECORE_DRM_BACKLIGHT_RAW))
|
|
|
|
found = EINA_TRUE;
|
2014-09-23 12:45:53 -07:00
|
|
|
|
|
|
|
eina_stringshare_del(devtype);
|
2014-12-10 06:59:48 -08:00
|
|
|
if (found) break;
|
2014-09-23 12:45:53 -07:00
|
|
|
}
|
|
|
|
|
2015-04-23 10:21:32 -07:00
|
|
|
if (found)
|
2014-09-23 12:45:53 -07:00
|
|
|
{
|
2015-04-23 10:21:32 -07:00
|
|
|
if ((backlight = calloc(1, sizeof(Ecore_Drm_Backlight))))
|
|
|
|
{
|
|
|
|
backlight->type = type;
|
|
|
|
backlight->device = eina_stringshare_add(device);
|
|
|
|
}
|
2014-09-23 05:28:08 -07:00
|
|
|
}
|
2014-09-24 06:59:23 -07:00
|
|
|
|
2014-12-10 07:00:13 -08:00
|
|
|
EINA_LIST_FREE(devs, device)
|
|
|
|
eina_stringshare_del(device);
|
2014-09-23 05:28:08 -07:00
|
|
|
|
|
|
|
return backlight;
|
|
|
|
}
|
|
|
|
|
2014-09-29 06:28:58 -07:00
|
|
|
static void
|
|
|
|
_ecore_drm_output_backlight_shutdown(Ecore_Drm_Backlight *backlight)
|
|
|
|
{
|
2014-12-10 07:04:22 -08:00
|
|
|
if (!backlight) return;
|
2014-09-29 06:28:58 -07:00
|
|
|
|
|
|
|
if (backlight->device)
|
|
|
|
eina_stringshare_del(backlight->device);
|
|
|
|
|
|
|
|
free(backlight);
|
|
|
|
}
|
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
static Ecore_Drm_Output *
|
2015-04-07 09:13:32 -07:00
|
|
|
_ecore_drm_output_create(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnector *conn, int x, int y, Eina_Bool cloned)
|
2014-03-06 01:43:48 -08:00
|
|
|
{
|
|
|
|
Ecore_Drm_Output *output;
|
2015-04-07 09:13:32 -07:00
|
|
|
int i = -1;
|
|
|
|
char name[DRM_CONNECTOR_NAME_LEN];
|
|
|
|
const char *type;
|
|
|
|
drmModeCrtc *crtc;
|
2014-03-06 01:43:48 -08:00
|
|
|
drmModeEncoder *enc;
|
|
|
|
drmModeModeInfo crtc_mode;
|
2015-04-22 18:11:51 -07:00
|
|
|
Ecore_Drm_Output_Mode *mode, *current = NULL, *preferred = NULL, *best = NULL;
|
2014-03-06 01:43:48 -08:00
|
|
|
Eina_List *l;
|
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
/* try to find a crtc for this connector */
|
2014-03-06 01:43:48 -08:00
|
|
|
i = _ecore_drm_output_crtc_find(dev, res, conn);
|
2015-04-07 09:13:32 -07:00
|
|
|
if (i < 0) return NULL;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
/* try to allocate space for new output */
|
|
|
|
if (!(output = calloc(1, sizeof(Ecore_Drm_Output)))) return NULL;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
|
|
|
output->x = x;
|
|
|
|
output->y = y;
|
2015-04-07 09:13:32 -07:00
|
|
|
output->dev = dev;
|
|
|
|
output->cloned = cloned;
|
2015-03-04 11:53:06 -08:00
|
|
|
output->phys_width = conn->mmWidth;
|
|
|
|
output->phys_height = conn->mmHeight;
|
2014-03-06 01:43:48 -08:00
|
|
|
output->subpixel = conn->subpixel;
|
2015-04-07 09:13:32 -07:00
|
|
|
|
|
|
|
output->make = eina_stringshare_add("UNKNOWN");
|
|
|
|
output->model = eina_stringshare_add("UNKNOWN");
|
|
|
|
output->name = eina_stringshare_add("UNKNOWN");
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-05-06 06:41:03 -07:00
|
|
|
output->connected = (conn->connection == DRM_MODE_CONNECTED);
|
2015-05-04 11:22:10 -07:00
|
|
|
output->conn_type = conn->connector_type;
|
2014-03-06 01:43:48 -08:00
|
|
|
if (conn->connector_type < ALEN(conn_types))
|
2015-04-07 09:13:32 -07:00
|
|
|
type = conn_types[conn->connector_type];
|
2014-03-06 01:43:48 -08:00
|
|
|
else
|
2015-04-07 09:13:32 -07:00
|
|
|
type = "UNKNOWN";
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
snprintf(name, sizeof(name), "%s-%d", type, conn->connector_type_id);
|
|
|
|
eina_stringshare_replace(&output->name, name);
|
2014-03-06 01:43:48 -08:00
|
|
|
|
|
|
|
output->crtc_id = res->crtcs[i];
|
2015-04-07 09:13:32 -07:00
|
|
|
output->pipe = i;
|
2014-03-06 01:43:48 -08:00
|
|
|
dev->crtc_allocator |= (1 << output->crtc_id);
|
|
|
|
output->conn_id = conn->connector_id;
|
2014-11-12 05:30:53 -08:00
|
|
|
dev->conn_allocator |= (1 << output->conn_id);
|
2015-04-07 09:13:32 -07:00
|
|
|
|
|
|
|
/* store original crtc so we can restore VT settings */
|
2014-03-06 01:43:48 -08:00
|
|
|
output->crtc = drmModeGetCrtc(dev->drm.fd, output->crtc_id);
|
2015-04-07 09:13:32 -07:00
|
|
|
|
|
|
|
/* get if dpms is supported */
|
2015-04-07 08:41:21 -07:00
|
|
|
output->dpms = _ecore_drm_output_property_get(dev->drm.fd, conn, "DPMS");
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
memset(&crtc_mode, 0, sizeof(crtc_mode));
|
|
|
|
|
|
|
|
/* get the encoder currently driving this connector */
|
2014-03-06 01:43:48 -08:00
|
|
|
if ((enc = drmModeGetEncoder(dev->drm.fd, conn->encoder_id)))
|
|
|
|
{
|
|
|
|
crtc = drmModeGetCrtc(dev->drm.fd, enc->crtc_id);
|
|
|
|
drmModeFreeEncoder(enc);
|
2015-04-07 09:13:32 -07:00
|
|
|
if (!crtc) goto err;
|
2014-03-06 01:43:48 -08:00
|
|
|
if (crtc->mode_valid) crtc_mode = crtc->mode;
|
|
|
|
drmModeFreeCrtc(crtc);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < conn->count_modes; i++)
|
|
|
|
{
|
|
|
|
if (!(mode = _ecore_drm_output_mode_add(output, &conn->modes[i])))
|
2015-04-07 09:13:32 -07:00
|
|
|
goto err;
|
2014-03-06 01:43:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EINA_LIST_REVERSE_FOREACH(output->modes, l, mode)
|
|
|
|
{
|
|
|
|
if (!memcmp(&crtc_mode, &mode->info, sizeof(crtc_mode)))
|
2015-04-07 09:13:32 -07:00
|
|
|
current = mode;
|
|
|
|
if (mode->flags & DRM_MODE_TYPE_PREFERRED)
|
|
|
|
preferred = mode;
|
|
|
|
best = mode;
|
2014-03-06 01:43:48 -08:00
|
|
|
}
|
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
if ((!current) && (crtc_mode.clock != 0))
|
2014-08-28 12:40:17 -07:00
|
|
|
{
|
2015-04-07 09:13:32 -07:00
|
|
|
if (!(current = _ecore_drm_output_mode_add(output, &crtc_mode)))
|
|
|
|
goto err;
|
2014-08-28 12:40:17 -07:00
|
|
|
}
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
if (current) output->current_mode = current;
|
|
|
|
else if (preferred) output->current_mode = preferred;
|
|
|
|
else if (best) output->current_mode = best;
|
2015-03-04 11:53:06 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
if (!output->current_mode) goto err;
|
|
|
|
|
|
|
|
output->current_mode->flags |= DRM_MODE_TYPE_DEFAULT;
|
|
|
|
|
|
|
|
if (drmModeSetCrtc(output->dev->drm.fd, output->crtc_id,
|
|
|
|
output->crtc->buffer_id, 0, 0,
|
|
|
|
&output->conn_id, 1, &output->current_mode->info) < 0)
|
2015-03-21 13:27:01 -07:00
|
|
|
{
|
2015-04-07 09:13:32 -07:00
|
|
|
ERR("Failed to set Mode %dx%d for Output %s: %m",
|
|
|
|
output->current_mode->width, output->current_mode->height,
|
|
|
|
output->name);
|
|
|
|
goto err;
|
2015-03-21 13:27:01 -07:00
|
|
|
}
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
/* try to init backlight */
|
2014-12-10 07:04:22 -08:00
|
|
|
output->backlight =
|
|
|
|
_ecore_drm_output_backlight_init(output, conn->connector_type);
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
/* parse edid */
|
|
|
|
_ecore_drm_output_edid_find(output, conn);
|
|
|
|
|
|
|
|
/* TODO: implement support for LCMS ? */
|
|
|
|
output->gamma = output->crtc->gamma_size;
|
|
|
|
|
|
|
|
dev->outputs = eina_list_append(dev->outputs, output);
|
|
|
|
|
2015-05-06 09:15:56 -07:00
|
|
|
/* NB: 'primary' output property is not supported in HW, so we need to
|
|
|
|
* implement it via software. As such, the First output which gets
|
|
|
|
* listed via libdrm will be assigned 'primary' until user changes
|
|
|
|
* it via config */
|
|
|
|
if (eina_list_count(dev->outputs) == 1)
|
|
|
|
output->primary = EINA_TRUE;
|
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
DBG("Created New Output At %d,%d", output->x, output->y);
|
|
|
|
DBG("\tCrtc Pos: %d %d", output->crtc->x, output->crtc->y);
|
|
|
|
DBG("\tCrtc: %d", output->crtc_id);
|
|
|
|
DBG("\tConn: %d", output->conn_id);
|
|
|
|
DBG("\tMake: %s", output->make);
|
|
|
|
DBG("\tModel: %s", output->model);
|
|
|
|
DBG("\tName: %s", output->name);
|
|
|
|
DBG("\tCloned: %d", output->cloned);
|
2015-05-06 09:15:56 -07:00
|
|
|
DBG("\tPrimary: %d", output->primary);
|
2015-04-07 09:13:32 -07:00
|
|
|
|
|
|
|
EINA_LIST_FOREACH(output->modes, l, mode)
|
|
|
|
{
|
|
|
|
DBG("\tAdded Mode: %dx%d@%.1f%s%s%s",
|
|
|
|
mode->width, mode->height, (mode->refresh / 1000.0),
|
|
|
|
(mode->flags & DRM_MODE_TYPE_PREFERRED) ? ", preferred" : "",
|
|
|
|
(mode->flags & DRM_MODE_TYPE_DEFAULT) ? ", current" : "",
|
|
|
|
(conn->count_modes == 0) ? ", built-in" : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
_ecore_drm_output_event_send(output, EINA_TRUE);
|
2015-02-19 11:47:34 -08:00
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
return output;
|
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
err:
|
2014-03-06 01:43:48 -08:00
|
|
|
EINA_LIST_FREE(output->modes, mode)
|
|
|
|
free(mode);
|
2015-04-07 08:41:21 -07:00
|
|
|
drmModeFreeProperty(output->dpms);
|
2014-03-06 01:43:48 -08:00
|
|
|
drmModeFreeCrtc(output->crtc);
|
|
|
|
dev->crtc_allocator &= ~(1 << output->crtc_id);
|
2014-11-12 05:30:53 -08:00
|
|
|
dev->conn_allocator &= ~(1 << output->conn_id);
|
2015-04-07 09:13:32 -07:00
|
|
|
eina_stringshare_del(output->name);
|
|
|
|
eina_stringshare_del(output->model);
|
|
|
|
eina_stringshare_del(output->make);
|
2014-03-06 01:43:48 -08:00
|
|
|
free(output);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-08-28 12:40:17 -07:00
|
|
|
static void
|
|
|
|
_ecore_drm_output_free(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
Ecore_Drm_Output_Mode *mode;
|
|
|
|
|
2014-10-22 06:12:29 -07:00
|
|
|
/* check for valid output */
|
2014-08-28 12:40:17 -07:00
|
|
|
if (!output) return;
|
|
|
|
|
2015-04-07 10:03:28 -07:00
|
|
|
if (output->pending_flip)
|
|
|
|
{
|
|
|
|
output->pending_destroy = EINA_TRUE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-23 05:28:14 -07:00
|
|
|
/* delete the backlight struct */
|
2014-10-23 05:28:33 -07:00
|
|
|
if (output->backlight)
|
|
|
|
_ecore_drm_output_backlight_shutdown(output->backlight);
|
2014-10-23 05:28:14 -07:00
|
|
|
|
2015-01-19 09:37:12 -08:00
|
|
|
/* turn off hardware cursor */
|
2015-04-07 09:13:32 -07:00
|
|
|
drmModeSetCursor(output->dev->drm.fd, output->crtc_id, 0, 0, 0);
|
2015-01-19 09:37:12 -08:00
|
|
|
|
|
|
|
/* restore crtc state */
|
|
|
|
if (output->crtc)
|
2015-04-07 09:13:32 -07:00
|
|
|
drmModeSetCrtc(output->dev->drm.fd, output->crtc->crtc_id,
|
2015-01-19 09:37:12 -08:00
|
|
|
output->crtc->buffer_id, output->crtc->x, output->crtc->y,
|
|
|
|
&output->conn_id, 1, &output->crtc->mode);
|
|
|
|
|
2014-10-22 06:12:29 -07:00
|
|
|
/* free modes */
|
2014-08-28 12:40:17 -07:00
|
|
|
EINA_LIST_FREE(output->modes, mode)
|
|
|
|
free(mode);
|
|
|
|
|
2014-10-22 06:12:29 -07:00
|
|
|
/* free strings */
|
|
|
|
if (output->name) eina_stringshare_del(output->name);
|
|
|
|
if (output->model) eina_stringshare_del(output->model);
|
|
|
|
if (output->make) eina_stringshare_del(output->make);
|
|
|
|
|
2015-04-07 08:41:21 -07:00
|
|
|
if (output->dpms) drmModeFreeProperty(output->dpms);
|
2014-10-22 06:13:44 -07:00
|
|
|
if (output->crtc) drmModeFreeCrtc(output->crtc);
|
2014-08-28 12:40:17 -07:00
|
|
|
|
|
|
|
free(output);
|
|
|
|
}
|
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
void
|
|
|
|
_ecore_drm_output_frame_finish(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
if (!output) return;
|
|
|
|
|
|
|
|
if (output->need_repaint) ecore_drm_output_repaint(output);
|
|
|
|
|
|
|
|
output->repaint_scheduled = EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb)
|
|
|
|
{
|
|
|
|
if ((!output) || (!fb)) return;
|
|
|
|
|
2015-04-07 11:07:12 -07:00
|
|
|
if ((fb->mmap) &&
|
|
|
|
(fb != output->dev->dumb[0]) && (fb != output->dev->dumb[1]))
|
2014-03-06 01:43:48 -08:00
|
|
|
ecore_drm_fb_destroy(fb);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_ecore_drm_output_repaint_start(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
unsigned int fb;
|
|
|
|
|
2014-03-12 03:41:57 -07:00
|
|
|
/* DBG("Output Repaint Start"); */
|
2014-03-06 01:43:48 -08:00
|
|
|
|
|
|
|
if (!output) return;
|
2015-04-07 10:03:28 -07:00
|
|
|
if (output->pending_destroy) return;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 11:07:12 -07:00
|
|
|
if (!output->dev->current)
|
2014-03-06 01:43:48 -08:00
|
|
|
{
|
2014-03-12 03:41:57 -07:00
|
|
|
/* DBG("\tNo Current FB"); */
|
2014-03-06 01:43:48 -08:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2015-04-07 11:07:12 -07:00
|
|
|
fb = output->dev->current->id;
|
2014-03-06 01:43:48 -08:00
|
|
|
if (drmModePageFlip(output->dev->drm.fd, output->crtc_id, fb,
|
|
|
|
DRM_MODE_PAGE_FLIP_EVENT, output) < 0)
|
|
|
|
{
|
|
|
|
ERR("Could not schedule output page flip event");
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
finish:
|
|
|
|
_ecore_drm_output_frame_finish(output);
|
|
|
|
}
|
|
|
|
|
2015-04-07 08:08:19 -07:00
|
|
|
void
|
|
|
|
_ecore_drm_outputs_update(Ecore_Drm_Device *dev)
|
2014-11-12 05:30:53 -08:00
|
|
|
{
|
|
|
|
drmModeRes *res;
|
2015-04-07 09:13:32 -07:00
|
|
|
drmModeConnector *conn;
|
|
|
|
int i = 0, x = 0, y = 0;
|
|
|
|
Ecore_Drm_Output *output;
|
2014-11-12 05:30:53 -08:00
|
|
|
uint32_t connected = 0, disconnects = 0;
|
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
/* try to get drm resources */
|
|
|
|
if (!(res = drmModeGetResources(dev->drm.fd))) return;
|
2014-11-12 05:30:53 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
/* find any new connects */
|
|
|
|
for (; i < res->count_connectors; i++)
|
2014-11-12 05:30:53 -08:00
|
|
|
{
|
2015-04-07 09:13:32 -07:00
|
|
|
int conn_id;
|
|
|
|
|
|
|
|
conn_id = res->connectors[i];
|
2014-11-12 05:30:53 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
/* try to get the connector */
|
|
|
|
if (!(conn = drmModeGetConnector(dev->drm.fd, conn_id)))
|
2014-11-12 05:30:53 -08:00
|
|
|
continue;
|
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
/* test if connected */
|
|
|
|
if (conn->connection != DRM_MODE_CONNECTED) goto next;
|
2014-11-12 05:30:53 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
connected |= (1 << conn_id);
|
2014-11-12 05:30:53 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
if (!(dev->conn_allocator & (1 << conn_id)))
|
2014-11-12 05:30:53 -08:00
|
|
|
{
|
2015-04-07 09:13:32 -07:00
|
|
|
if (eina_list_count(dev->outputs) > 0)
|
2014-11-12 05:30:53 -08:00
|
|
|
{
|
2015-04-07 09:13:32 -07:00
|
|
|
Ecore_Drm_Output *last;
|
2014-11-12 05:30:53 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
if ((last = eina_list_last_data_get(dev->outputs)))
|
|
|
|
x = last->x + last->current_mode->width;
|
|
|
|
else
|
|
|
|
x = 0;
|
2014-11-12 05:30:53 -08:00
|
|
|
}
|
2015-04-07 09:13:32 -07:00
|
|
|
else
|
|
|
|
x = 0;
|
|
|
|
|
|
|
|
/* try to create a new output */
|
|
|
|
/* NB: hotplugged outputs will be set to cloned by default */
|
|
|
|
if (!(output =
|
|
|
|
_ecore_drm_output_create(dev, res, conn, x, y, EINA_TRUE)))
|
|
|
|
goto next;
|
2014-11-12 05:30:53 -08:00
|
|
|
}
|
2015-04-07 09:13:32 -07:00
|
|
|
next:
|
|
|
|
drmModeFreeConnector(conn);
|
2014-11-12 05:30:53 -08:00
|
|
|
}
|
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
drmModeFreeResources(res);
|
|
|
|
|
|
|
|
/* find any disconnects */
|
|
|
|
disconnects = (dev->conn_allocator & ~connected);
|
2014-11-12 05:30:53 -08:00
|
|
|
if (disconnects)
|
|
|
|
{
|
2015-04-07 09:13:32 -07:00
|
|
|
Eina_List *l;
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(dev->outputs, l, output)
|
2014-11-12 05:30:53 -08:00
|
|
|
{
|
2015-04-07 09:13:32 -07:00
|
|
|
if (disconnects & (1 << output->conn_id))
|
2014-11-12 05:30:53 -08:00
|
|
|
{
|
2015-04-07 09:13:32 -07:00
|
|
|
disconnects &= ~(1 << output->conn_id);
|
|
|
|
_ecore_drm_output_event_send(output, EINA_FALSE);
|
|
|
|
ecore_drm_output_free(output);
|
2014-11-12 05:30:53 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-06 06:33:17 -07:00
|
|
|
static void
|
|
|
|
_ecore_drm_output_planes_get(Ecore_Drm_Device *dev)
|
|
|
|
{
|
|
|
|
drmModePlaneRes *pres;
|
|
|
|
unsigned int i = 0, j = 0;
|
|
|
|
int k = 0;
|
|
|
|
|
|
|
|
pres = drmModeGetPlaneResources(dev->drm.fd);
|
|
|
|
if (!pres) return;
|
|
|
|
|
|
|
|
for (; i < pres->count_planes; i++)
|
|
|
|
{
|
|
|
|
drmModePlane *plane;
|
|
|
|
drmModeObjectPropertiesPtr props;
|
|
|
|
int type = -1;
|
|
|
|
|
|
|
|
plane = drmModeGetPlane(dev->drm.fd, pres->planes[i]);
|
|
|
|
if (!plane) continue;
|
|
|
|
|
|
|
|
props = drmModeObjectGetProperties(dev->drm.fd, plane->plane_id,
|
|
|
|
DRM_MODE_OBJECT_PLANE);
|
|
|
|
if (!props) goto free_plane;
|
|
|
|
|
|
|
|
DBG("Plane %u Properties:", plane->plane_id);
|
|
|
|
|
|
|
|
for (j = 0; type == -1 && j < props->count_props; j++)
|
|
|
|
{
|
|
|
|
drmModePropertyPtr prop;
|
|
|
|
|
|
|
|
prop = drmModeGetProperty(dev->drm.fd, props->props[j]);
|
|
|
|
if (!prop) continue;
|
|
|
|
|
|
|
|
if (!strcmp(prop->name, "type"))
|
2015-05-06 08:31:25 -07:00
|
|
|
type = props->prop_values[j];
|
2015-05-06 06:33:17 -07:00
|
|
|
|
|
|
|
drmModeFreeProperty(prop);
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG("\tFormats:");
|
|
|
|
for (j = 0; j < plane->count_formats; j++)
|
|
|
|
DBG("\t\t%4.4s", (char *)&plane->formats[j]);
|
|
|
|
|
|
|
|
for (j = 0; j < props->count_props; j++ )
|
|
|
|
{
|
|
|
|
drmModePropertyPtr prop;
|
|
|
|
|
|
|
|
prop = drmModeGetProperty(dev->drm.fd, props->props[j]);
|
|
|
|
if (!prop) continue;
|
|
|
|
|
|
|
|
DBG("\tProperty Name: %s", prop->name);
|
|
|
|
|
|
|
|
if (prop->flags & DRM_MODE_PROP_RANGE)
|
|
|
|
{
|
|
|
|
DBG("\t\tRange Property");
|
|
|
|
for (k = 0; k < prop->count_values; k++)
|
|
|
|
DBG("\t\t\t%"PRIu64, prop->values[k]);
|
|
|
|
}
|
|
|
|
if (prop->flags & DRM_MODE_PROP_ENUM)
|
|
|
|
{
|
|
|
|
DBG("\t\tEnum Property");
|
|
|
|
for (k = 0; k < prop->count_enums; k++)
|
|
|
|
DBG("\t\t\t%s=%llu", prop->enums[k].name,
|
|
|
|
prop->enums[k].value);
|
|
|
|
}
|
|
|
|
if (prop->flags & DRM_MODE_PROP_BITMASK)
|
|
|
|
{
|
|
|
|
DBG("\t\tBitmask Property");
|
|
|
|
for (k = 0; k < prop->count_enums; k++)
|
|
|
|
DBG("\t\t\t%s=0x%llx", prop->enums[k].name,
|
|
|
|
(1LL << prop->enums[k].value));
|
|
|
|
}
|
|
|
|
|
2015-05-06 08:31:25 -07:00
|
|
|
DBG("\t\tValue: %"PRIu64, props->prop_values[j]);
|
2015-05-06 06:33:17 -07:00
|
|
|
|
|
|
|
drmModeFreeProperty(prop);
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG("\tCurrent Crtc: %d", plane->crtc_id);
|
|
|
|
DBG("\tPossible Crtcs: 0x%08x", plane->possible_crtcs);
|
|
|
|
|
|
|
|
drmModeFreeObjectProperties(props);
|
|
|
|
|
|
|
|
free_plane:
|
|
|
|
drmModeFreePlane(plane);
|
|
|
|
}
|
|
|
|
|
|
|
|
drmModeFreePlaneResources(pres);
|
|
|
|
}
|
|
|
|
|
2014-10-23 05:52:02 -07:00
|
|
|
/* public functions */
|
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
/**
|
2014-03-15 04:03:08 -07:00
|
|
|
* @defgroup Ecore_Drm_Output_Group Ecore DRM Output
|
|
|
|
*
|
|
|
|
* Functions to manage DRM outputs.
|
2014-03-06 01:43:48 -08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ecore_drm_outputs_create(Ecore_Drm_Device *dev)
|
|
|
|
{
|
|
|
|
Eina_Bool ret = EINA_TRUE;
|
2014-10-21 05:18:34 -07:00
|
|
|
Ecore_Drm_Output *output = NULL;
|
2014-03-06 01:43:48 -08:00
|
|
|
drmModeConnector *conn;
|
|
|
|
drmModeRes *res;
|
|
|
|
int i = 0, x = 0, y = 0;
|
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(dev, EINA_FALSE);
|
2015-04-24 09:51:34 -07:00
|
|
|
EINA_SAFETY_ON_TRUE_RETURN_VAL(dev->drm.fd < 0, EINA_FALSE);
|
2015-04-07 09:13:32 -07:00
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
/* DBG("Create outputs for %d", dev->drm.fd); */
|
|
|
|
|
|
|
|
/* get the resources */
|
|
|
|
if (!(res = drmModeGetResources(dev->drm.fd)))
|
|
|
|
{
|
|
|
|
ERR("Could not get resources for drm card: %m");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(dev->crtcs = calloc(res->count_crtcs, sizeof(unsigned int))))
|
|
|
|
{
|
|
|
|
ERR("Could not allocate space for crtcs");
|
|
|
|
/* free resources */
|
|
|
|
drmModeFreeResources(res);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->crtc_count = res->count_crtcs;
|
|
|
|
memcpy(dev->crtcs, res->crtcs, sizeof(unsigned int) * res->count_crtcs);
|
|
|
|
|
|
|
|
dev->min_width = res->min_width;
|
|
|
|
dev->min_height = res->min_height;
|
|
|
|
dev->max_width = res->max_width;
|
|
|
|
dev->max_height = res->max_height;
|
|
|
|
|
2015-05-06 06:33:17 -07:00
|
|
|
/* DBG("Dev Size"); */
|
|
|
|
/* DBG("\tMin Width: %u", res->min_width); */
|
|
|
|
/* DBG("\tMin Height: %u", res->min_height); */
|
|
|
|
/* DBG("\tMax Width: %u", res->max_width); */
|
|
|
|
/* DBG("\tMax Height: %u", res->max_height); */
|
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
for (i = 0; i < res->count_connectors; i++)
|
|
|
|
{
|
|
|
|
/* get the connector */
|
|
|
|
if (!(conn = drmModeGetConnector(dev->drm.fd, res->connectors[i])))
|
|
|
|
continue;
|
|
|
|
|
2015-05-04 11:13:21 -07:00
|
|
|
/* if (conn->connection != DRM_MODE_CONNECTED) goto next; */
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
/* create output for this connector */
|
|
|
|
if (!(output =
|
|
|
|
_ecore_drm_output_create(dev, res, conn, x, y, EINA_FALSE)))
|
|
|
|
goto next;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
x += output->current_mode->width;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
next:
|
2014-03-06 01:43:48 -08:00
|
|
|
/* free the connector */
|
|
|
|
drmModeFreeConnector(conn);
|
|
|
|
}
|
|
|
|
|
2015-04-07 09:13:32 -07:00
|
|
|
/* TODO: Planes */
|
2015-05-06 06:33:17 -07:00
|
|
|
_ecore_drm_output_planes_get(dev);
|
2015-04-07 09:13:32 -07:00
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
ret = EINA_TRUE;
|
|
|
|
if (eina_list_count(dev->outputs) < 1)
|
2015-04-07 09:13:32 -07:00
|
|
|
ret = EINA_FALSE;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
|
|
|
/* free resources */
|
|
|
|
drmModeFreeResources(res);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_free(Ecore_Drm_Output *output)
|
|
|
|
{
|
2014-10-22 06:12:29 -07:00
|
|
|
_ecore_drm_output_free(output);
|
2014-03-06 01:43:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_cursor_size_set(Ecore_Drm_Output *output, int handle, int w, int h)
|
|
|
|
{
|
2015-04-24 09:51:34 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output);
|
2015-04-07 09:13:32 -07:00
|
|
|
drmModeSetCursor(output->dev->drm.fd, output->crtc_id, handle, w, h);
|
2014-03-06 01:43:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ecore_drm_output_enable(Ecore_Drm_Output *output)
|
|
|
|
{
|
2015-04-07 11:07:12 -07:00
|
|
|
Ecore_Drm_Device *dev;
|
2014-03-06 01:43:48 -08:00
|
|
|
Ecore_Drm_Output_Mode *mode;
|
2015-04-07 11:07:12 -07:00
|
|
|
int x = 0, y = 0;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 11:07:12 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
|
2015-04-24 09:51:34 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output->dev, EINA_FALSE);
|
2015-04-07 11:07:12 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output->current_mode, EINA_FALSE);
|
|
|
|
|
2015-04-24 09:51:34 -07:00
|
|
|
dev = output->dev;
|
2015-04-07 11:07:12 -07:00
|
|
|
|
|
|
|
output->enabled = EINA_TRUE;
|
|
|
|
if (!dev->current)
|
|
|
|
{
|
|
|
|
/* schedule repaint */
|
|
|
|
/* NB: this will trigger a redraw at next idle */
|
|
|
|
output->need_repaint = EINA_TRUE;
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 08:41:21 -07:00
|
|
|
ecore_drm_output_dpms_set(output, DRM_MODE_DPMS_ON);
|
|
|
|
|
2015-04-07 11:07:12 -07:00
|
|
|
if (!output->cloned)
|
|
|
|
{
|
|
|
|
x = output->x;
|
|
|
|
y = output->y;
|
|
|
|
}
|
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
mode = output->current_mode;
|
2015-04-07 11:07:12 -07:00
|
|
|
if (drmModeSetCrtc(dev->drm.fd, output->crtc_id, dev->current->id, x, y,
|
|
|
|
&output->conn_id, 1, &mode->info) < 0)
|
2014-03-06 01:43:48 -08:00
|
|
|
{
|
2015-04-07 11:07:12 -07:00
|
|
|
ERR("Failed to set Mode %dx%d for Output %s: %m",
|
|
|
|
mode->width, mode->height, output->name);
|
2014-03-06 01:43:48 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2015-04-07 11:21:30 -07:00
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_disable(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output);
|
|
|
|
|
|
|
|
output->enabled = EINA_FALSE;
|
|
|
|
output->need_repaint = EINA_FALSE;
|
|
|
|
ecore_drm_output_cursor_size_set(output, 0, 0, 0);
|
|
|
|
ecore_drm_output_dpms_set(output, DRM_MODE_DPMS_OFF);
|
|
|
|
}
|
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb)
|
|
|
|
{
|
2015-04-24 09:51:34 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(fb);
|
2015-04-07 11:07:12 -07:00
|
|
|
_ecore_drm_output_fb_release(output, fb);
|
2014-03-06 01:43:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_repaint(Ecore_Drm_Output *output)
|
|
|
|
{
|
2015-04-07 11:07:12 -07:00
|
|
|
Ecore_Drm_Device *dev;
|
2014-03-06 01:43:48 -08:00
|
|
|
Ecore_Drm_Sprite *sprite;
|
2015-04-07 11:07:12 -07:00
|
|
|
Eina_List *l;
|
2014-03-06 01:43:48 -08:00
|
|
|
int ret = 0;
|
|
|
|
|
2015-04-07 10:03:28 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output);
|
2015-04-24 09:51:34 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output->dev);
|
2015-04-07 10:03:28 -07:00
|
|
|
EINA_SAFETY_ON_TRUE_RETURN(output->pending_destroy);
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-24 09:51:34 -07:00
|
|
|
dev = output->dev;
|
2015-04-07 11:07:12 -07:00
|
|
|
|
2014-03-12 03:41:57 -07:00
|
|
|
/* DBG("Output Repaint: %d %d", output->crtc_id, output->conn_id); */
|
2014-03-06 01:43:48 -08:00
|
|
|
|
|
|
|
/* TODO: assign planes ? */
|
|
|
|
|
2015-04-07 11:07:12 -07:00
|
|
|
if (!dev->next)
|
2014-12-10 07:04:22 -08:00
|
|
|
_ecore_drm_output_software_render(output);
|
2015-04-07 11:07:12 -07:00
|
|
|
if (!dev->next) return;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
|
|
|
output->need_repaint = EINA_FALSE;
|
|
|
|
|
2015-04-07 11:07:12 -07:00
|
|
|
if ((!dev->current) ||
|
|
|
|
(dev->current->stride != dev->next->stride))
|
2014-03-06 01:43:48 -08:00
|
|
|
{
|
|
|
|
Ecore_Drm_Output_Mode *mode;
|
|
|
|
|
|
|
|
mode = output->current_mode;
|
2015-04-07 11:07:12 -07:00
|
|
|
ret = drmModeSetCrtc(dev->drm.fd, output->crtc_id, dev->next->id,
|
|
|
|
0, 0, &output->conn_id, 1, &mode->info);
|
2014-12-10 07:04:22 -08:00
|
|
|
if (ret) goto err;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 11:07:12 -07:00
|
|
|
ecore_drm_output_dpms_set(output, DRM_MODE_DPMS_ON);
|
|
|
|
}
|
2015-01-19 09:37:12 -08:00
|
|
|
|
2015-04-07 11:07:12 -07:00
|
|
|
if (drmModePageFlip(dev->drm.fd, output->crtc_id, dev->next->id,
|
2014-03-06 01:43:48 -08:00
|
|
|
DRM_MODE_PAGE_FLIP_EVENT, output) < 0)
|
|
|
|
{
|
2015-04-07 11:07:12 -07:00
|
|
|
ERR("Could not schedule pageflip: %m");
|
|
|
|
DBG("\tCrtc: %d\tConn: %d\tFB: %d",
|
|
|
|
output->crtc_id, output->conn_id, dev->next->id);
|
2014-03-06 01:43:48 -08:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
output->pending_flip = EINA_TRUE;
|
|
|
|
|
2015-04-07 11:07:12 -07:00
|
|
|
/* TODO: output_cursor_set */
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(dev->sprites, l, sprite)
|
2014-03-06 01:43:48 -08:00
|
|
|
{
|
|
|
|
unsigned int flags = 0, id = 0;
|
|
|
|
drmVBlank vbl =
|
|
|
|
{
|
|
|
|
.request.type = (DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT),
|
|
|
|
.request.sequence = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (((!sprite->current_fb) && (!sprite->next_fb)) ||
|
|
|
|
(!ecore_drm_sprites_crtc_supported(output, sprite->crtcs)))
|
|
|
|
continue;
|
|
|
|
|
2015-04-07 11:07:12 -07:00
|
|
|
if ((sprite->next_fb) && (!dev->cursors_broken))
|
2014-03-06 01:43:48 -08:00
|
|
|
id = sprite->next_fb->id;
|
|
|
|
|
|
|
|
ecore_drm_sprites_fb_set(sprite, id, flags);
|
|
|
|
|
|
|
|
vbl.request.signal = (unsigned long)sprite;
|
2015-04-07 11:07:12 -07:00
|
|
|
ret = drmWaitVBlank(dev->drm.fd, &vbl);
|
2014-03-06 01:43:48 -08:00
|
|
|
if (ret) ERR("Error Wait VBlank: %m");
|
|
|
|
|
|
|
|
sprite->output = output;
|
|
|
|
output->pending_vblank = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
err:
|
2015-04-07 11:07:12 -07:00
|
|
|
if (dev->next)
|
2014-03-06 01:43:48 -08:00
|
|
|
{
|
2015-04-07 11:07:12 -07:00
|
|
|
_ecore_drm_output_fb_release(output, dev->next);
|
|
|
|
dev->next = NULL;
|
2014-03-06 01:43:48 -08:00
|
|
|
}
|
|
|
|
}
|
2014-03-28 03:32:59 -07:00
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_size_get(Ecore_Drm_Device *dev, int output, int *w, int *h)
|
|
|
|
{
|
|
|
|
drmModeFB *fb;
|
|
|
|
|
|
|
|
if (w) *w = 0;
|
|
|
|
if (h) *h = 0;
|
2015-04-24 09:51:34 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(dev);
|
2014-03-28 03:32:59 -07:00
|
|
|
|
|
|
|
if (!(fb = drmModeGetFB(dev->drm.fd, output))) return;
|
|
|
|
if (w) *w = fb->width;
|
|
|
|
if (h) *h = fb->height;
|
|
|
|
drmModeFreeFB(fb);
|
|
|
|
}
|
2014-09-04 07:02:24 -07:00
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_outputs_geometry_get(Ecore_Drm_Device *dev, int *x, int *y, int *w, int *h)
|
|
|
|
{
|
|
|
|
Ecore_Drm_Output *output;
|
|
|
|
Eina_List *l;
|
|
|
|
int ox = 0, oy = 0, ow = 0, oh = 0;
|
|
|
|
|
|
|
|
if (x) *x = 0;
|
|
|
|
if (y) *y = 0;
|
|
|
|
if (w) *w = 0;
|
|
|
|
if (h) *h = 0;
|
2015-04-24 09:51:34 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(dev);
|
2014-09-04 07:02:24 -07:00
|
|
|
|
|
|
|
EINA_LIST_FOREACH(dev->outputs, l, output)
|
|
|
|
{
|
2015-04-07 10:10:35 -07:00
|
|
|
if (output->cloned) continue;
|
2014-09-04 07:02:24 -07:00
|
|
|
ow += MAX(ow, output->current_mode->width);
|
2015-04-07 09:32:15 -07:00
|
|
|
oh = MAX(oh, output->current_mode->height);
|
2014-09-04 07:02:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (x) *x = ox;
|
|
|
|
if (y) *y = oy;
|
|
|
|
if (w) *w = ow;
|
|
|
|
if (h) *h = oh;
|
|
|
|
}
|
2015-02-19 11:47:26 -08:00
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_position_get(Ecore_Drm_Output *output, int *x, int *y)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output);
|
|
|
|
|
|
|
|
if (x) *x = output->x;
|
|
|
|
if (y) *y = output->y;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_current_resolution_get(Ecore_Drm_Output *output, int *w, int *h, unsigned int *refresh)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output);
|
|
|
|
|
|
|
|
if (w) *w = output->current_mode->width;
|
|
|
|
if (h) *h = output->current_mode->height;
|
|
|
|
if (refresh) *refresh = output->current_mode->refresh;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_physical_size_get(Ecore_Drm_Output *output, int *w, int *h)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output);
|
|
|
|
|
2015-03-04 11:53:06 -08:00
|
|
|
if (w) *w = output->phys_width;
|
|
|
|
if (h) *h = output->phys_height;
|
2015-02-19 11:47:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI unsigned int
|
|
|
|
ecore_drm_output_subpixel_order_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0);
|
|
|
|
|
|
|
|
return output->subpixel;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Stringshare *
|
|
|
|
ecore_drm_output_model_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
|
|
|
|
|
|
|
|
return output->model;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Stringshare *
|
|
|
|
ecore_drm_output_make_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
|
|
|
|
|
|
|
|
return output->make;
|
|
|
|
}
|
2015-04-07 08:41:21 -07:00
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_dpms_set(Ecore_Drm_Output *output, int level)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output);
|
2015-04-24 09:51:34 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output->dev);
|
2015-04-07 08:41:21 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output->dpms);
|
|
|
|
|
|
|
|
drmModeConnectorSetProperty(output->dev->drm.fd, output->conn_id,
|
|
|
|
output->dpms->prop_id, level);
|
|
|
|
}
|
2015-04-07 09:24:07 -07:00
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_gamma_set(Ecore_Drm_Output *output, uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output);
|
2015-04-24 09:51:34 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output->dev);
|
2015-04-07 09:24:07 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output->crtc);
|
|
|
|
|
|
|
|
if (output->gamma != size) return;
|
|
|
|
|
|
|
|
if (drmModeCrtcSetGamma(output->dev->drm.fd, output->crtc_id, size, r, g, b))
|
|
|
|
ERR("Failed to set output gamma: %m");
|
|
|
|
}
|
2015-04-08 07:49:46 -07:00
|
|
|
|
2015-04-08 07:59:35 -07:00
|
|
|
EAPI unsigned int
|
|
|
|
ecore_drm_output_crtc_id_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0);
|
|
|
|
|
|
|
|
return output->crtc_id;
|
|
|
|
}
|
|
|
|
|
2015-04-08 07:49:46 -07:00
|
|
|
EAPI unsigned int
|
|
|
|
ecore_drm_output_crtc_buffer_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
drmModeCrtc *crtc;
|
|
|
|
unsigned int id = 0;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0);
|
2015-04-24 09:51:34 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output->dev, 0);
|
2015-04-08 07:49:46 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output->crtc, 0);
|
|
|
|
|
|
|
|
if (!(crtc = drmModeGetCrtc(output->dev->drm.fd, output->crtc_id)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
id = crtc->buffer_id;
|
|
|
|
drmModeFreeCrtc(crtc);
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
2015-04-08 08:01:52 -07:00
|
|
|
|
|
|
|
EAPI unsigned int
|
|
|
|
ecore_drm_output_connector_id_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0);
|
|
|
|
|
|
|
|
return output->conn_id;
|
|
|
|
}
|
2015-05-04 11:06:31 -07:00
|
|
|
|
|
|
|
EAPI char *
|
|
|
|
ecore_drm_output_name_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
|
|
|
|
|
|
|
|
return strdup(output->name);
|
|
|
|
}
|
2015-05-04 11:13:21 -07:00
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ecore_drm_output_connected_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
|
|
|
|
|
|
|
|
return output->connected;
|
|
|
|
}
|
2015-05-04 11:26:47 -07:00
|
|
|
|
|
|
|
EAPI unsigned int
|
|
|
|
ecore_drm_output_connector_type_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0);
|
|
|
|
|
|
|
|
return output->conn_type;
|
|
|
|
}
|
2015-05-04 11:41:18 -07:00
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ecore_drm_output_backlight_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
|
|
|
|
return (output->backlight != NULL);
|
|
|
|
}
|
2015-05-04 12:03:47 -07:00
|
|
|
|
|
|
|
EAPI char *
|
|
|
|
ecore_drm_output_edid_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
2015-05-12 08:56:52 -07:00
|
|
|
char *edid_str = NULL;
|
|
|
|
|
2015-05-04 12:03:47 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output->edid_blob, NULL);
|
|
|
|
|
2015-05-12 08:56:52 -07:00
|
|
|
edid_str = malloc((128 * 2) + 1);
|
|
|
|
if (edid_str)
|
|
|
|
{
|
|
|
|
unsigned int k, kk;
|
|
|
|
const char *hexch = "0123456789abcdef";
|
|
|
|
|
|
|
|
for (kk = 0, k = 0; k < 128; k++)
|
|
|
|
{
|
|
|
|
edid_str[kk] = hexch[(output->edid_blob[k] >> 4) & 0xf];
|
|
|
|
edid_str[kk + 1] = hexch[output->edid_blob[k] & 0xf];
|
|
|
|
kk += 2;
|
|
|
|
}
|
|
|
|
edid_str[kk] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return edid_str;
|
2015-05-04 12:03:47 -07:00
|
|
|
}
|
2015-05-05 06:12:25 -07:00
|
|
|
|
|
|
|
EAPI Eina_List *
|
|
|
|
ecore_drm_output_modes_get(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output->modes, NULL);
|
|
|
|
|
|
|
|
return output->modes;
|
|
|
|
}
|
2015-05-06 09:22:15 -07:00
|
|
|
|
|
|
|
EAPI Ecore_Drm_Output *
|
|
|
|
ecore_drm_output_primary_get(Ecore_Drm_Device *dev)
|
|
|
|
{
|
|
|
|
Ecore_Drm_Output *ret;
|
|
|
|
const Eina_List *l;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(dev, NULL);
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(dev->outputs, l, ret)
|
|
|
|
if (ret->primary) return ret;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-05-06 10:19:08 -07:00
|
|
|
|
2015-05-07 08:37:54 -07:00
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_primary_set(Ecore_Drm_Output *output)
|
|
|
|
{
|
|
|
|
const Eina_List *l;
|
|
|
|
Ecore_Drm_Output *out;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output);
|
|
|
|
|
|
|
|
/* unmark all outputs as primary */
|
|
|
|
EINA_LIST_FOREACH(output->dev->outputs, l, out)
|
|
|
|
out->primary = EINA_FALSE;
|
|
|
|
|
|
|
|
/* mark this output as primary */
|
|
|
|
output->primary = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2015-05-06 10:19:08 -07:00
|
|
|
EAPI void
|
|
|
|
ecore_drm_output_crtc_size_get(Ecore_Drm_Output *output, int *width, int *height)
|
|
|
|
{
|
|
|
|
if (width) *width = 0;
|
|
|
|
if (height) *height = 0;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(output);
|
|
|
|
|
|
|
|
if (width) *width = output->crtc->width;
|
|
|
|
if (height) *height = output->crtc->height;
|
|
|
|
}
|
2015-05-11 09:37:24 -07:00
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
ecore_drm_output_possible_crtc_get(Ecore_Drm_Output *output, unsigned int crtc)
|
|
|
|
{
|
|
|
|
Ecore_Drm_Device *dev;
|
|
|
|
drmModeRes *res;
|
|
|
|
drmModeConnector *conn;
|
|
|
|
drmModeEncoder *enc;
|
|
|
|
int i, j;
|
|
|
|
unsigned int p;
|
|
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output->dev, EINA_FALSE);
|
|
|
|
|
|
|
|
dev = output->dev;
|
|
|
|
EINA_SAFETY_ON_TRUE_RETURN_VAL(dev->drm.fd < 0, EINA_FALSE);
|
|
|
|
|
|
|
|
/* get the resources */
|
|
|
|
if (!(res = drmModeGetResources(dev->drm.fd)))
|
|
|
|
{
|
|
|
|
ERR("Could not get resources for drm card: %m");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < res->count_connectors; i++)
|
|
|
|
{
|
|
|
|
/* get the connector */
|
|
|
|
if (!(conn = drmModeGetConnector(dev->drm.fd, res->connectors[i])))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 0; j < conn->count_encoders; j++)
|
|
|
|
{
|
|
|
|
/* get the encoder on this connector */
|
|
|
|
if (!(enc = drmModeGetEncoder(dev->drm.fd, conn->encoders[j])))
|
|
|
|
{
|
|
|
|
WRN("Failed to get encoder: %m");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the encoder for given crtc */
|
|
|
|
if (enc->crtc_id != crtc) goto next;
|
|
|
|
|
|
|
|
p = enc->possible_crtcs;
|
|
|
|
|
|
|
|
/* Does the CRTC match the list of possible CRTCs from the encoder? */
|
|
|
|
if (p & (1 << output->crtc_id))
|
|
|
|
ret = EINA_TRUE;
|
|
|
|
|
|
|
|
next:
|
|
|
|
drmModeFreeEncoder(enc);
|
|
|
|
if (ret) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free the connector */
|
|
|
|
drmModeFreeConnector(conn);
|
|
|
|
if (ret) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free resources */
|
|
|
|
drmModeFreeResources(res);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|