efl/src/lib/ecore_drm2/ecore_drm2_connectors.c

268 lines
7.1 KiB
C

#include "ecore_drm2_private.h"
#ifndef DRM_MODE_CONNECTOR_WRITEBACK
# define DRM_MODE_CONNECTOR_WRITEBACK 18
#endif
static Eina_Thread_Queue *thq = NULL;
typedef struct
{
Eina_Thread_Queue_Msg head;
Ecore_Drm2_Thread_Op_Code code;
} Thread_Msg;
static void
_ecore_drm2_connector_state_thread_send(Ecore_Drm2_Thread_Op_Code code)
{
Thread_Msg *msg;
void *ref;
msg = eina_thread_queue_send(thq, sizeof(Thread_Msg), &ref);
msg->code = code;
eina_thread_queue_send_done(thq, ref);
}
static void
_ecore_drm2_connector_state_debug(Ecore_Drm2_Connector *conn)
{
DBG("Connector Atomic State Fill Complete");
DBG("\tConnector: %d", conn->state->obj_id);
DBG("\t\tCrtc Id: %lu", (long)conn->state->crtc.value);
DBG("\t\tDPMS: %lu", (long)conn->state->dpms.value);
DBG("\t\tAspect Ratio: %lu", (long)conn->state->aspect.value);
DBG("\t\tScaling Mode: %lu", (long)conn->state->scaling.value);
}
static void
_ecore_drm2_connector_state_fill(Ecore_Drm2_Connector *conn)
{
Ecore_Drm2_Connector_State *cstate;
drmModeObjectPropertiesPtr oprops;
unsigned int i = 0;
/* try to allocate space for connector Atomic state */
conn->state = calloc(1, sizeof(Ecore_Drm2_Connector_State));
if (!conn->state)
{
ERR("Could not allocate space for Connector state");
return;
}
cstate = conn->state;
cstate->obj_id = conn->id;
/* get the properties of this connector from drm */
oprops =
sym_drmModeObjectGetProperties(conn->fd, cstate->obj_id,
DRM_MODE_OBJECT_CONNECTOR);
if (!oprops)
{
free(conn->state);
return;
}
for (; i < oprops->count_props; i++)
{
drmModePropertyPtr prop;
/* try to get this individual property */
prop = sym_drmModeGetProperty(conn->fd, oprops->props[i]);
if (!prop) continue;
/* check for the properties we are interested in */
if (!strcmp(prop->name, "CRTC_ID"))
{
cstate->crtc.id = prop->prop_id;
cstate->crtc.value = oprops->prop_values[i];
}
else if (!strcmp(prop->name, "DPMS"))
{
cstate->dpms.id = prop->prop_id;
cstate->dpms.value = oprops->prop_values[i];
}
else if (!strcmp(prop->name, "EDID"))
{
drmModePropertyBlobPtr bp;
cstate->edid.id = oprops->prop_values[i];
if (!cstate->edid.id)
{
cstate->edid.len = 0;
goto cont;
}
bp = sym_drmModeGetPropertyBlob(conn->fd, cstate->edid.id);
if (!bp) goto cont;
if ((!cstate->edid.data) ||
memcmp(cstate->edid.data, bp->data, bp->length) != 0)
{
cstate->edid.data = eina_memdup(bp->data, bp->length, 1);
}
cstate->edid.len = bp->length;
if (cstate->edid.id != 0)
sym_drmModeCreatePropertyBlob(conn->fd, bp->data, bp->length,
&cstate->edid.id);
sym_drmModeFreePropertyBlob(bp);
}
else if (!strcmp(prop->name, "aspect ratio"))
{
cstate->aspect.id = prop->prop_id;
cstate->aspect.value = oprops->prop_values[i];
}
else if (!strcmp(prop->name, "scaling mode"))
{
cstate->scaling.id = prop->prop_id;
cstate->scaling.value = oprops->prop_values[i];
}
cont:
sym_drmModeFreeProperty(prop);
}
sym_drmModeFreeObjectProperties(oprops);
/* send message to thread for debug printing connector state */
_ecore_drm2_connector_state_thread_send(ECORE_DRM2_THREAD_CODE_DEBUG);
}
static void
_ecore_drm2_connector_state_commit(Ecore_Drm2_Connector *conn EINA_UNUSED)
{
DBG("Connector State Commit");
}
static void
_ecore_drm2_connector_state_thread(void *data, Ecore_Thread *thread)
{
Ecore_Drm2_Connector *conn;
Thread_Msg *msg;
void *ref;
conn = data;
eina_thread_name_set(eina_thread_self(), "Ecore-drm2-connector");
while (!ecore_thread_check(thread))
{
msg = eina_thread_queue_wait(thq, &ref);
if (msg)
{
switch (msg->code)
{
case ECORE_DRM2_THREAD_CODE_FILL:
_ecore_drm2_connector_state_fill(conn);
break;
case ECORE_DRM2_THREAD_CODE_COMMIT:
_ecore_drm2_connector_state_commit(conn);
break;
case ECORE_DRM2_THREAD_CODE_DEBUG:
_ecore_drm2_connector_state_debug(conn);
break;
default:
break;
}
eina_thread_queue_wait_done(thq, ref);
}
}
}
static void
_ecore_drm2_connector_state_thread_notify(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED, void *msg)
{
free(msg);
}
static Ecore_Drm2_Connector *
_ecore_drm2_connector_create(Ecore_Drm2_Device *dev, drmModeConnector *conn, uint32_t id)
{
Ecore_Drm2_Connector *c;
/* try to allocate space for new connector */
c = calloc(1, sizeof(Ecore_Drm2_Connector));
if (!c) return NULL;
c->id = id;
c->fd = dev->fd;
c->drmConn = conn;
c->type = conn->connector_type;
/* check if this connector is a writeback */
if (conn->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
c->writeback = EINA_TRUE;
/* append this connector to list */
dev->conns = eina_list_append(dev->conns, c);
return c;
}
Eina_Bool
_ecore_drm2_connectors_create(Ecore_Drm2_Device *dev)
{
Ecore_Drm2_Connector *c;
drmModeConnector *conn;
drmModeRes *res;
int i = 0;
/* try to get drm resources */
res = sym_drmModeGetResources(dev->fd);
if (!res) return EINA_FALSE;
/* TOOD: set dev->min/max width & height ? */
thq = eina_thread_queue_new();
for (; i < res->count_connectors; i++)
{
uint32_t conn_id;
conn_id = res->connectors[i];
/* try to get this connector from drm */
conn = sym_drmModeGetConnector(dev->fd, conn_id);
if (!conn) continue;
/* try to create a new connector */
c = _ecore_drm2_connector_create(dev, conn, conn_id);
if (!c) goto err;
/* NB: Use an explicit thread to fill crtc atomic state */
c->thread =
ecore_thread_feedback_run(_ecore_drm2_connector_state_thread,
_ecore_drm2_connector_state_thread_notify,
NULL, NULL, c, EINA_TRUE);
}
sym_drmModeFreeResources(res);
return EINA_TRUE;
err:
_ecore_drm2_connectors_destroy(dev);
sym_drmModeFreeConnector(conn);
sym_drmModeFreeResources(res);
return EINA_FALSE;
}
void
_ecore_drm2_connectors_destroy(Ecore_Drm2_Device *dev)
{
Ecore_Drm2_Connector *conn;
EINA_LIST_FREE(dev->conns, conn)
{
if (conn->thread) ecore_thread_cancel(conn->thread);
if (conn->drmConn) sym_drmModeFreeConnector(conn->drmConn);
free(conn->state);
free(conn);
}
eina_thread_queue_free(thq);
thq = NULL;
}