forked from enlightenment/efl
ecore-drm: Add Ecore_Drm code
@feature: Add Ecore_Drm library code for setting up drm card, outputs, virtual terminals, framebuffers, and input for use with ecore_evas drm code. Signed-off-by: Chris Michael <cp.michael@samsung.com>
This commit is contained in:
parent
0f1883df9a
commit
3762e85c39
|
@ -0,0 +1,171 @@
|
||||||
|
#ifndef _ECORE_DRM_H
|
||||||
|
# define _ECORE_DRM_H
|
||||||
|
|
||||||
|
# ifdef EAPI
|
||||||
|
# undef EAPI
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# ifdef BUILDING_DLL
|
||||||
|
# define EAPI __declspec(dllexport)
|
||||||
|
# else // ifdef BUILDING_DLL
|
||||||
|
# define EAPI __declspec(dllimport)
|
||||||
|
# endif // ifdef BUILDING_DLL
|
||||||
|
#else // ifdef _MSC_VER
|
||||||
|
# ifdef __GNUC__
|
||||||
|
# if __GNUC__ >= 4
|
||||||
|
# define EAPI __attribute__ ((visibility("default")))
|
||||||
|
# else // if __GNUC__ >= 4
|
||||||
|
# define EAPI
|
||||||
|
# endif // if __GNUC__ >= 4
|
||||||
|
# else // ifdef __GNUC__
|
||||||
|
# define EAPI
|
||||||
|
# endif // ifdef __GNUC__
|
||||||
|
#endif // ifdef _MSC_VER
|
||||||
|
|
||||||
|
typedef enum _Ecore_Drm_Op
|
||||||
|
{
|
||||||
|
ECORE_DRM_OP_READ_FD_SET,
|
||||||
|
ECORE_DRM_OP_WRITE_FD_SET,
|
||||||
|
ECORE_DRM_OP_DEVICE_OPEN,
|
||||||
|
ECORE_DRM_OP_DEVICE_CLOSE,
|
||||||
|
ECORE_DRM_OP_DEVICE_MASTER_DROP,
|
||||||
|
ECORE_DRM_OP_DEVICE_MASTER_SET,
|
||||||
|
ECORE_DRM_OP_TTY_OPEN,
|
||||||
|
ECORE_DRM_OP_TTY_CLOSE
|
||||||
|
} Ecore_Drm_Op;
|
||||||
|
|
||||||
|
typedef enum _Ecore_Drm_Op_Result
|
||||||
|
{
|
||||||
|
ECORE_DRM_OP_SUCCESS,
|
||||||
|
ECORE_DRM_OP_FAILURE
|
||||||
|
} Ecore_Drm_Op_Result;
|
||||||
|
|
||||||
|
typedef enum _Ecore_Drm_Evdev_Capabilities
|
||||||
|
{
|
||||||
|
EVDEV_KEYBOARD = (1 << 0),
|
||||||
|
EVDEV_BUTTON = (1 << 1),
|
||||||
|
EVDEV_MOTION_ABS = (1 << 2),
|
||||||
|
EVDEV_MOTION_REL = (1 << 3),
|
||||||
|
EVDEV_TOUCH = (1 << 4),
|
||||||
|
} Ecore_Drm_Evdev_Capabilities;
|
||||||
|
|
||||||
|
typedef enum _Ecore_Drm_Evdev_Event_Type
|
||||||
|
{
|
||||||
|
EVDEV_NONE,
|
||||||
|
EVDEV_ABSOLUTE_TOUCH_DOWN,
|
||||||
|
EVDEV_ABSOLUTE_MOTION,
|
||||||
|
EVDEV_ABSOLUTE_TOUCH_UP,
|
||||||
|
EVDEV_ABSOLUTE_MT_DOWN,
|
||||||
|
EVDEV_ABSOLUTE_MT_MOTION,
|
||||||
|
EVDEV_ABSOLUTE_MT_UP,
|
||||||
|
EVDEV_RELATIVE_MOTION,
|
||||||
|
} Ecore_Drm_Evdev_Event_Type;
|
||||||
|
|
||||||
|
typedef enum _Ecore_Drm_Seat_Capabilities
|
||||||
|
{
|
||||||
|
EVDEV_SEAT_POINTER = (1 << 0),
|
||||||
|
EVDEV_SEAT_KEYBOARD = (1 << 1),
|
||||||
|
EVDEV_SEAT_TOUCH = (1 << 2),
|
||||||
|
} Ecore_Drm_Seat_Capabilities;
|
||||||
|
|
||||||
|
/* structure for message passing */
|
||||||
|
typedef struct _Ecore_Drm_Message
|
||||||
|
{
|
||||||
|
int opcode, size;
|
||||||
|
void *data;
|
||||||
|
} Ecore_Drm_Message;
|
||||||
|
|
||||||
|
/* structure for fb objects */
|
||||||
|
typedef struct _Ecore_Drm_Fb
|
||||||
|
{
|
||||||
|
Eina_Bool from_client : 1;
|
||||||
|
unsigned int id, hdl;
|
||||||
|
unsigned int stride, size;
|
||||||
|
int fd;
|
||||||
|
void *mmap;
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* struct gbm_bo *bo; */
|
||||||
|
/* #endif */
|
||||||
|
} Ecore_Drm_Fb;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm device */
|
||||||
|
typedef struct _Ecore_Drm_Device Ecore_Drm_Device;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm output mode */
|
||||||
|
typedef struct _Ecore_Drm_Output_Mode Ecore_Drm_Output_Mode;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm output */
|
||||||
|
typedef struct _Ecore_Drm_Output Ecore_Drm_Output;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm udev input */
|
||||||
|
typedef struct _Ecore_Drm_Input Ecore_Drm_Input;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm evdev input */
|
||||||
|
typedef struct _Ecore_Drm_Evdev Ecore_Drm_Evdev;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm seat */
|
||||||
|
typedef struct _Ecore_Drm_Seat Ecore_Drm_Seat;
|
||||||
|
|
||||||
|
/* opaque structure to represent a drm sprite */
|
||||||
|
typedef struct _Ecore_Drm_Sprite Ecore_Drm_Sprite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Ecore functions for dealing with drm, virtual terminals
|
||||||
|
*
|
||||||
|
* @defgroup Ecore_Drm_Group Ecore_Drm - Drm Integration
|
||||||
|
* @ingroup Ecore
|
||||||
|
*
|
||||||
|
* Ecore_Drm provides a wrapper and functions for using libdrm
|
||||||
|
*
|
||||||
|
* @li @ref Ecore_Drm_Init_Group
|
||||||
|
* @li @ref Ecore_Drm_Device_Group
|
||||||
|
* @li @ref Ecore_Drm_Tty_Group
|
||||||
|
* @li @ref Ecore_Drm_Output_Group
|
||||||
|
* @li @ref Ecore_Drm_Input_Group
|
||||||
|
* @li @ref Ecore_Drm_Sprite_Group
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
EAPI int ecore_drm_init(void);
|
||||||
|
EAPI int ecore_drm_shutdown(void);
|
||||||
|
|
||||||
|
/* EAPI void *ecore_drm_gbm_get(Ecore_Drm_Device *dev); */
|
||||||
|
/* EAPI unsigned int ecore_drm_gbm_format_get(Ecore_Drm_Device *dev); */
|
||||||
|
|
||||||
|
EAPI Ecore_Drm_Device *ecore_drm_device_find(const char *name, const char *seat);
|
||||||
|
EAPI void ecore_drm_device_free(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_device_open(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_device_close(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_device_master_get(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_device_master_set(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_device_master_drop(Ecore_Drm_Device *dev);
|
||||||
|
EAPI int ecore_drm_device_fd_get(Ecore_Drm_Device *dev);
|
||||||
|
|
||||||
|
EAPI Eina_Bool ecore_drm_tty_open(Ecore_Drm_Device *dev, const char *name);
|
||||||
|
EAPI Eina_Bool ecore_drm_tty_close(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_tty_release(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_tty_acquire(Ecore_Drm_Device *dev);
|
||||||
|
|
||||||
|
EAPI Eina_Bool ecore_drm_outputs_create(Ecore_Drm_Device *dev);
|
||||||
|
EAPI void ecore_drm_output_free(Ecore_Drm_Output *output);
|
||||||
|
EAPI void ecore_drm_output_cursor_size_set(Ecore_Drm_Output *output, int handle, int w, int h);
|
||||||
|
EAPI Eina_Bool ecore_drm_output_enable(Ecore_Drm_Output *output);
|
||||||
|
EAPI void ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb);
|
||||||
|
EAPI void ecore_drm_output_repaint(Ecore_Drm_Output *output);
|
||||||
|
|
||||||
|
EAPI Eina_Bool ecore_drm_inputs_create(Ecore_Drm_Device *dev);
|
||||||
|
EAPI void ecore_drm_inputs_destroy(Ecore_Drm_Device *dev);
|
||||||
|
EAPI Eina_Bool ecore_drm_inputs_enable(Ecore_Drm_Input *input);
|
||||||
|
EAPI void ecore_drm_inputs_disable(Ecore_Drm_Input *input);
|
||||||
|
|
||||||
|
EAPI Eina_Bool ecore_drm_sprites_create(Ecore_Drm_Device *dev);
|
||||||
|
EAPI void ecore_drm_sprites_destroy(Ecore_Drm_Device *dev);
|
||||||
|
EAPI void ecore_drm_sprites_fb_set(Ecore_Drm_Sprite *sprite, int fb_id, int flags);
|
||||||
|
EAPI Eina_Bool ecore_drm_sprites_crtc_supported(Ecore_Drm_Output *output, unsigned int supported);
|
||||||
|
|
||||||
|
EAPI Ecore_Drm_Fb *ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height);
|
||||||
|
EAPI void ecore_drm_fb_destroy(Ecore_Drm_Fb *fb);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,414 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#define RIGHTS_LEN CMSG_LEN(sizeof(int))
|
||||||
|
|
||||||
|
#define IOVSET(_iov, _addr, _len) \
|
||||||
|
(_iov)->iov_base = (void *)(_addr); \
|
||||||
|
(_iov)->iov_len = (_len);
|
||||||
|
|
||||||
|
/* local variables */
|
||||||
|
static int _ecore_drm_init_count = 0;
|
||||||
|
static int _ecore_drm_sockets[2] = { -1, -1 };
|
||||||
|
static struct cmsghdr *cmsgptr = NULL;
|
||||||
|
|
||||||
|
/* external variables */
|
||||||
|
struct udev *udev;
|
||||||
|
int _ecore_drm_log_dom = -1;
|
||||||
|
#ifdef LOG_TO_FILE
|
||||||
|
FILE *lg;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_sockets_create(void)
|
||||||
|
{
|
||||||
|
if (_ecore_drm_sockets[0] > -1) return EINA_TRUE;
|
||||||
|
|
||||||
|
/* create a pair of sequenced sockets (fixed-length)
|
||||||
|
* NB: when reading from one of these, it is required that we read
|
||||||
|
* an entire packet with each read() call */
|
||||||
|
if (socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_NONBLOCK,
|
||||||
|
0, _ecore_drm_sockets) < 0)
|
||||||
|
{
|
||||||
|
ERR("Socketpair Failed: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NB: We don't want cloexec for the sockets. That would cause them to be
|
||||||
|
* closed when we exec the child process but we need them open so that
|
||||||
|
* we can pass messages */
|
||||||
|
/* if (fcntl(_ecore_drm_sockets[0], F_SETFD, FD_CLOEXEC) < 0) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Failed to set CLOEXEC: %m"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* DBG("Parent Socket: %d", _ecore_drm_sockets[0]); */
|
||||||
|
/* DBG("Child Socket: %d", _ecore_drm_sockets[1]); */
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_launcher_spawn(void)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
if ((pid = fork()) < 0) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (pid == 0)
|
||||||
|
{
|
||||||
|
char renv[64], wenv[64], buff[PATH_MAX];
|
||||||
|
char *args[1] = { NULL };
|
||||||
|
sigset_t mask;
|
||||||
|
|
||||||
|
/* read socket for slave is 1 */
|
||||||
|
snprintf(renv, sizeof(renv), "ECORE_DRM_LAUNCHER_SOCKET_READ=%d",
|
||||||
|
_ecore_drm_sockets[1]);
|
||||||
|
|
||||||
|
/* write socket for slave is 0 */
|
||||||
|
snprintf(wenv, sizeof(wenv), "ECORE_DRM_LAUNCHER_SOCKET_WRITE=%d",
|
||||||
|
_ecore_drm_sockets[0]);
|
||||||
|
|
||||||
|
/* assemble exec path */
|
||||||
|
snprintf(buff, sizeof(buff),
|
||||||
|
"%s/ecore_drm/bin/%s/ecore_drm_launch",
|
||||||
|
PACKAGE_LIB_DIR, MODULE_ARCH);
|
||||||
|
|
||||||
|
/* don't give our signal mask to the child */
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigaddset(&mask, SIGTERM);
|
||||||
|
sigaddset(&mask, SIGCHLD);
|
||||||
|
sigaddset(&mask, SIGINT);
|
||||||
|
sigaddset(&mask, SIGTTIN);
|
||||||
|
sigaddset(&mask, SIGTTOU);
|
||||||
|
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||||
|
|
||||||
|
/* NB: We need to use execve here so that capabilities are inherited.
|
||||||
|
* Also, this should set Our (ecore_drm) effective uid to be the
|
||||||
|
* owner of the launched process (setuid in this case) */
|
||||||
|
char *ev[3] = { strdup(renv), strdup(wenv), NULL };
|
||||||
|
execve(buff, args, ev);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
while (waitpid(pid, &status, WNOHANG) < 0)
|
||||||
|
if (errno != EINTR) break;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
_ecore_drm_socket_send(int opcode, int fd, void *data, size_t bytes)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Message dmsg;
|
||||||
|
struct iovec iov[2];
|
||||||
|
struct msghdr msg;
|
||||||
|
ssize_t size;
|
||||||
|
|
||||||
|
/* Simplified version of sending messages. We don't need to send any
|
||||||
|
* 'credentials' with this as it is just basically an IPC to send over
|
||||||
|
* our request to the slave process */
|
||||||
|
|
||||||
|
/* NB: Hmm, don't think we need to set any socket options here */
|
||||||
|
|
||||||
|
memset(&dmsg, 0, sizeof(dmsg));
|
||||||
|
|
||||||
|
IOVSET(iov + 0, &dmsg, sizeof(dmsg));
|
||||||
|
IOVSET(iov + 1, &data, bytes);
|
||||||
|
|
||||||
|
dmsg.opcode = opcode;
|
||||||
|
dmsg.size = bytes;
|
||||||
|
|
||||||
|
msg.msg_name = NULL;
|
||||||
|
msg.msg_namelen = 0;
|
||||||
|
msg.msg_iov = iov;
|
||||||
|
msg.msg_iovlen = 2;
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
|
if ((!cmsgptr) && (!(cmsgptr = malloc(RIGHTS_LEN))))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cmsgptr->cmsg_level = SOL_SOCKET;
|
||||||
|
cmsgptr->cmsg_type = SCM_RIGHTS;
|
||||||
|
cmsgptr->cmsg_len = RIGHTS_LEN;
|
||||||
|
|
||||||
|
msg.msg_control = cmsgptr;
|
||||||
|
msg.msg_controllen = RIGHTS_LEN;
|
||||||
|
|
||||||
|
if (fd > -1)
|
||||||
|
*((int *)CMSG_DATA(cmsgptr)) = fd;
|
||||||
|
else
|
||||||
|
*((int *)CMSG_DATA(cmsgptr)) = _ecore_drm_sockets[1];
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
size = sendmsg(_ecore_drm_sockets[1], &msg, MSG_EOR);
|
||||||
|
if (errno != 0)
|
||||||
|
{
|
||||||
|
DBG("Error Sending Message: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DBG("Sent %li bytes to Socket %d", size, _ecore_drm_sockets[1]); */
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_ecore_drm_socket_receive(int opcode EINA_UNUSED, int *fd, void **data, size_t bytes)
|
||||||
|
{
|
||||||
|
int ret = ECORE_DRM_OP_FAILURE;
|
||||||
|
Ecore_Drm_Message dmsg;
|
||||||
|
struct cmsghdr *cmsg;
|
||||||
|
struct iovec iov[2];
|
||||||
|
struct msghdr msg;
|
||||||
|
char buff[CMSG_SPACE(sizeof(fd))];
|
||||||
|
/* ssize_t size; */
|
||||||
|
|
||||||
|
memset(&dmsg, 0, sizeof(dmsg));
|
||||||
|
memset(&buff, 0, sizeof(buff));
|
||||||
|
|
||||||
|
IOVSET(iov + 0, &dmsg, sizeof(dmsg));
|
||||||
|
IOVSET(iov + 1, &buff, sizeof(buff));
|
||||||
|
|
||||||
|
msg.msg_name = NULL;
|
||||||
|
msg.msg_namelen = 0;
|
||||||
|
msg.msg_iov = iov;
|
||||||
|
msg.msg_iovlen = 2;
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
|
if ((!cmsgptr) && (!(cmsgptr = malloc(RIGHTS_LEN))))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
msg.msg_control = cmsgptr;
|
||||||
|
msg.msg_controllen = RIGHTS_LEN;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
recvmsg(_ecore_drm_sockets[0], &msg, 0);
|
||||||
|
if (errno != 0)
|
||||||
|
{
|
||||||
|
ERR("Failed to receive message: %m");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DBG("Received %li bytes from %d", size, _ecore_drm_sockets[0]); */
|
||||||
|
|
||||||
|
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||||
|
cmsg = CMSG_NXTHDR(&msg, cmsg))
|
||||||
|
{
|
||||||
|
if (cmsg->cmsg_level != SOL_SOCKET)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (cmsg->cmsg_type)
|
||||||
|
{
|
||||||
|
case SCM_RIGHTS:
|
||||||
|
if (fd) *fd = *((int *)CMSG_DATA(cmsg));
|
||||||
|
switch (dmsg.opcode)
|
||||||
|
{
|
||||||
|
case ECORE_DRM_OP_DEVICE_OPEN:
|
||||||
|
case ECORE_DRM_OP_DEVICE_CLOSE:
|
||||||
|
case ECORE_DRM_OP_TTY_OPEN:
|
||||||
|
case ECORE_DRM_OP_DEVICE_MASTER_DROP:
|
||||||
|
case ECORE_DRM_OP_DEVICE_MASTER_SET:
|
||||||
|
if ((fd) && (*fd >= 0)) ret = ECORE_DRM_OP_SUCCESS;
|
||||||
|
if (data) memcpy(*data, buff, bytes);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_ecore_drm_message_send(int opcode, int fd, void *data, size_t bytes)
|
||||||
|
{
|
||||||
|
_ecore_drm_socket_send(opcode, fd, data, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
Eina_Bool
|
||||||
|
_ecore_drm_message_receive(int opcode, int *fd, void **data, size_t bytes)
|
||||||
|
{
|
||||||
|
int ret = ECORE_DRM_OP_FAILURE;
|
||||||
|
|
||||||
|
ret = _ecore_drm_socket_receive(opcode, fd, data, bytes);
|
||||||
|
if (ret != ECORE_DRM_OP_SUCCESS) return EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Init_Group Drm Library Init and Shutdown Functions
|
||||||
|
*
|
||||||
|
* Functions that start and shutdown the Ecore_Drm Library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the Ecore_Drm library
|
||||||
|
*
|
||||||
|
* @return The number of times the library has been initialized without
|
||||||
|
* being shut down. 0 is returned if an error occurs.
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Init_Group
|
||||||
|
*/
|
||||||
|
EAPI int
|
||||||
|
ecore_drm_init(void)
|
||||||
|
{
|
||||||
|
/* if we have already initialized, return the count */
|
||||||
|
if (++_ecore_drm_init_count != 1) return _ecore_drm_init_count;
|
||||||
|
|
||||||
|
/* try to init eina */
|
||||||
|
if (!eina_init()) return --_ecore_drm_init_count;
|
||||||
|
|
||||||
|
if (!ecore_init())
|
||||||
|
{
|
||||||
|
eina_shutdown();
|
||||||
|
return --_ecore_drm_init_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set logging level */
|
||||||
|
eina_log_level_set(EINA_LOG_LEVEL_DBG);
|
||||||
|
|
||||||
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
|
setvbuf(stderr, NULL, _IONBF, 0);
|
||||||
|
|
||||||
|
/* optionally log output to a file */
|
||||||
|
#ifdef LOG_TO_FILE
|
||||||
|
int log_fd;
|
||||||
|
char log_path[PATH_MAX];
|
||||||
|
mode_t um;
|
||||||
|
|
||||||
|
/* assemble logging file path */
|
||||||
|
strcpy(log_path, "/tmp/ecore_drm_XXXXXX");
|
||||||
|
|
||||||
|
/* create temporary logging file */
|
||||||
|
um = umask(S_IRWXG | S_IRWXO);
|
||||||
|
log_fd = mkstemp(log_path);
|
||||||
|
umask(um);
|
||||||
|
|
||||||
|
/* try to open logging file */
|
||||||
|
if (!(lg = fdopen(log_fd, "w")))
|
||||||
|
goto log_err;
|
||||||
|
|
||||||
|
eina_log_print_cb_set(eina_log_print_cb_file, lg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* try to create logging domain */
|
||||||
|
_ecore_drm_log_dom =
|
||||||
|
eina_log_domain_register("ecore_drm", ECORE_DRM_DEFAULT_LOG_COLOR);
|
||||||
|
if (!_ecore_drm_log_dom)
|
||||||
|
{
|
||||||
|
EINA_LOG_ERR("Could not create log domain for Ecore_Drm");
|
||||||
|
goto log_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set default logging level for this domain */
|
||||||
|
if (!eina_log_domain_level_check(_ecore_drm_log_dom, EINA_LOG_LEVEL_DBG))
|
||||||
|
eina_log_domain_level_set("ecore_drm", EINA_LOG_LEVEL_DBG);
|
||||||
|
|
||||||
|
/* try to init udev */
|
||||||
|
if (!(udev = udev_new()))
|
||||||
|
goto udev_err;
|
||||||
|
|
||||||
|
/* try to create the socketpair */
|
||||||
|
if (!_ecore_drm_sockets_create())
|
||||||
|
goto sock_err;
|
||||||
|
|
||||||
|
/* try to run Spartacus */
|
||||||
|
if (!_ecore_drm_launcher_spawn())
|
||||||
|
goto spawn_err;
|
||||||
|
|
||||||
|
/* return init count */
|
||||||
|
return _ecore_drm_init_count;
|
||||||
|
|
||||||
|
spawn_err:
|
||||||
|
close(_ecore_drm_sockets[0]);
|
||||||
|
close(_ecore_drm_sockets[1]);
|
||||||
|
sock_err:
|
||||||
|
if (udev) udev_unref(udev);
|
||||||
|
udev_err:
|
||||||
|
ecore_shutdown();
|
||||||
|
eina_log_domain_unregister(_ecore_drm_log_dom);
|
||||||
|
_ecore_drm_log_dom = -1;
|
||||||
|
log_err:
|
||||||
|
#ifdef LOG_TO_FILE
|
||||||
|
if (lg) fclose(lg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* shutdown eina */
|
||||||
|
eina_shutdown();
|
||||||
|
|
||||||
|
return --_ecore_drm_init_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown the Ecore_Drm library.
|
||||||
|
*
|
||||||
|
* @return The number of times the library has been initialized without
|
||||||
|
* being shutdown. 0 is returned if an error occurs.
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Init_Group
|
||||||
|
*/
|
||||||
|
EAPI int
|
||||||
|
ecore_drm_shutdown(void)
|
||||||
|
{
|
||||||
|
/* if we are still in use, decrement init count and get out */
|
||||||
|
if (--_ecore_drm_init_count != 0) return _ecore_drm_init_count;
|
||||||
|
|
||||||
|
/* close udev handle */
|
||||||
|
if (udev) udev_unref(udev);
|
||||||
|
|
||||||
|
/* close sockets */
|
||||||
|
close(_ecore_drm_sockets[0]);
|
||||||
|
close(_ecore_drm_sockets[1]);
|
||||||
|
|
||||||
|
ecore_shutdown();
|
||||||
|
|
||||||
|
/* unregsiter log domain */
|
||||||
|
eina_log_domain_unregister(_ecore_drm_log_dom);
|
||||||
|
_ecore_drm_log_dom = -1;
|
||||||
|
|
||||||
|
#ifdef LOG_TO_FILE
|
||||||
|
if (lg) fclose(lg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* shutdown eina */
|
||||||
|
eina_shutdown();
|
||||||
|
|
||||||
|
/* return init count */
|
||||||
|
return _ecore_drm_init_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void *
|
||||||
|
ecore_drm_gbm_get(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
if (!dev) return NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_GBM
|
||||||
|
return dev->gbm;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI unsigned int
|
||||||
|
ecore_drm_gbm_format_get(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
if (!dev) return 0;
|
||||||
|
return dev->format;
|
||||||
|
}
|
|
@ -0,0 +1,583 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* static Eina_Bool */
|
||||||
|
/* _ecore_drm_device_egl_config_get(Ecore_Drm_Device *dev, const EGLint *attribs, const EGLint *visual) */
|
||||||
|
/* { */
|
||||||
|
/* EGLint c = 0, m = 0; */
|
||||||
|
/* EGLConfig *cfgs; */
|
||||||
|
/* int i = 0; */
|
||||||
|
|
||||||
|
/* if (!eglGetConfigs(dev->egl.disp, NULL, 0, &c) || (c < 1)) */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
|
||||||
|
/* if (!(cfgs = calloc(c, sizeof(*cfgs)))) return EINA_FALSE; */
|
||||||
|
|
||||||
|
/* if (!eglChooseConfig(dev->egl.disp, attribs, cfgs, c, &m)) */
|
||||||
|
/* { */
|
||||||
|
/* free(cfgs); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* for (i = 0; i < m; i++) */
|
||||||
|
/* { */
|
||||||
|
/* EGLint id; */
|
||||||
|
|
||||||
|
/* if (visual) */
|
||||||
|
/* { */
|
||||||
|
/* if (!eglGetConfigAttrib(dev->egl.disp, cfgs[i], */
|
||||||
|
/* EGL_NATIVE_VISUAL_ID, &id)) */
|
||||||
|
/* continue; */
|
||||||
|
|
||||||
|
/* if ((id != 0) && (id != *visual)) */
|
||||||
|
/* continue; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* dev->egl.cfg = cfgs[i]; */
|
||||||
|
/* free(cfgs); */
|
||||||
|
/* return EINA_TRUE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* free(cfgs); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
static void
|
||||||
|
_ecore_drm_device_cb_page_flip(int fd EINA_UNUSED, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
|
||||||
|
DBG("Drm Page Flip Event");
|
||||||
|
|
||||||
|
if (!(output = data)) return;
|
||||||
|
|
||||||
|
if (output->pending_flip)
|
||||||
|
{
|
||||||
|
ecore_drm_output_fb_release(output, output->current);
|
||||||
|
output->current = output->next;
|
||||||
|
output->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->pending_flip = EINA_FALSE;
|
||||||
|
if (!output->pending_vblank) ecore_drm_output_repaint(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_ecore_drm_device_cb_vblank(int fd EINA_UNUSED, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Sprite *sprite;
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
|
||||||
|
DBG("Drm VBlank Event");
|
||||||
|
|
||||||
|
if (!(sprite = data)) return;
|
||||||
|
|
||||||
|
output = sprite->output;
|
||||||
|
output->pending_vblank = EINA_FALSE;
|
||||||
|
|
||||||
|
ecore_drm_output_fb_release(output, sprite->current_fb);
|
||||||
|
sprite->current_fb = sprite->next_fb;
|
||||||
|
sprite->next_fb = NULL;
|
||||||
|
|
||||||
|
if (!output->pending_flip) _ecore_drm_output_frame_finish(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_device_cb_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
drmEventContext ctx;
|
||||||
|
|
||||||
|
if (!(dev = data)) return ECORE_CALLBACK_RENEW;
|
||||||
|
|
||||||
|
DBG("Drm Device Event");
|
||||||
|
|
||||||
|
memset(&ctx, 0, sizeof(ctx));
|
||||||
|
|
||||||
|
ctx.version = DRM_EVENT_CONTEXT_VERSION;
|
||||||
|
ctx.page_flip_handler = _ecore_drm_device_cb_page_flip;
|
||||||
|
ctx.vblank_handler = _ecore_drm_device_cb_vblank;
|
||||||
|
|
||||||
|
drmHandleEvent(dev->drm.fd, &ctx);
|
||||||
|
|
||||||
|
return ECORE_CALLBACK_RENEW;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_device_cb_idle(void *data)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
if (!(dev = data)) return ECORE_CALLBACK_CANCEL;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(dev->outputs, l, output)
|
||||||
|
{
|
||||||
|
output->need_repaint = EINA_TRUE;
|
||||||
|
if (output->repaint_scheduled) continue;
|
||||||
|
_ecore_drm_output_repaint_start(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ECORE_CALLBACK_RENEW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Device_Group Device manipulation functions
|
||||||
|
*
|
||||||
|
* Functions that deal with finding, opening, closing, and otherwise using
|
||||||
|
* the DRM device itself.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a drm device in the system.
|
||||||
|
*
|
||||||
|
* @param name The name of the device to find. If NULL, this function will
|
||||||
|
* search for the default drm device.
|
||||||
|
* @param seat The name of the seat where this device may be found. If NULL,
|
||||||
|
* this function will use a default seat name 'seat0'.
|
||||||
|
*
|
||||||
|
* @return An opaque Ecore_Drm_Device structure representing the card.
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Ecore_Drm_Device *
|
||||||
|
ecore_drm_device_find(const char *name, const char *seat)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev = NULL;
|
||||||
|
struct udev_enumerate *uenum;
|
||||||
|
struct udev_list_entry *uentry;
|
||||||
|
struct udev_device *udevice, *tmpdevice = NULL, *pcidevice;
|
||||||
|
const char *path = NULL, *devseat = NULL;
|
||||||
|
|
||||||
|
/* check for existing udev reference */
|
||||||
|
if (!udev) return NULL;
|
||||||
|
|
||||||
|
/* setup udev enumerator */
|
||||||
|
uenum = udev_enumerate_new(udev);
|
||||||
|
udev_enumerate_add_match_subsystem(uenum, "drm");
|
||||||
|
udev_enumerate_add_match_subsystem(uenum, "card[0-9]*");
|
||||||
|
|
||||||
|
/* ask udev for list of drm devices */
|
||||||
|
udev_enumerate_scan_devices(uenum);
|
||||||
|
|
||||||
|
/* loop list of returned devices */
|
||||||
|
udev_list_entry_foreach(uentry, udev_enumerate_get_list_entry(uenum))
|
||||||
|
{
|
||||||
|
/* get device path */
|
||||||
|
path = udev_list_entry_get_name(uentry);
|
||||||
|
|
||||||
|
/* get udev device */
|
||||||
|
if (!(udevice = udev_device_new_from_syspath(udev, path)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* if we are looking for a certain device, then compare names */
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
if (strcmp(name, udev_device_get_devnode(udevice)))
|
||||||
|
{
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get this devices' seat */
|
||||||
|
devseat = udev_device_get_property_value(udevice, "ID_SEAT");
|
||||||
|
if (!devseat) devseat = "seat0";
|
||||||
|
|
||||||
|
/* if we are looking for a device on a certain seat, compare it */
|
||||||
|
if (seat)
|
||||||
|
{
|
||||||
|
if (strcmp(seat, devseat))
|
||||||
|
{
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* no seat name passed to use. check default */
|
||||||
|
if (strcmp(devseat, "seat0"))
|
||||||
|
{
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to find the boot_vga attribute */
|
||||||
|
if ((pcidevice =
|
||||||
|
udev_device_get_parent_with_subsystem_devtype(udevice, "pci", NULL)))
|
||||||
|
{
|
||||||
|
const char *id;
|
||||||
|
|
||||||
|
if ((id = udev_device_get_sysattr_value(pcidevice, "boot_vga")))
|
||||||
|
{
|
||||||
|
if (!strcmp(id, "1"))
|
||||||
|
{
|
||||||
|
if (tmpdevice) udev_device_unref(tmpdevice);
|
||||||
|
tmpdevice = udevice;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tmpdevice)
|
||||||
|
tmpdevice = udevice;
|
||||||
|
else
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* destroy the enumerator */
|
||||||
|
udev_enumerate_unref(uenum);
|
||||||
|
|
||||||
|
if (tmpdevice)
|
||||||
|
{
|
||||||
|
DBG("Found Drm Device");
|
||||||
|
DBG("\tFilename: %s", udev_device_get_devnode(tmpdevice));
|
||||||
|
DBG("\tDriver: %s", udev_device_get_driver(tmpdevice));
|
||||||
|
DBG("\tDevpath: %s", udev_device_get_devpath(tmpdevice));
|
||||||
|
DBG("\tSyspath: %s", udev_device_get_syspath(tmpdevice));
|
||||||
|
DBG("\tSysname: %s", udev_device_get_sysname(tmpdevice));
|
||||||
|
|
||||||
|
/* try to allocate space for return device structure */
|
||||||
|
if ((dev = calloc(1, sizeof(Ecore_Drm_Device))))
|
||||||
|
{
|
||||||
|
const char *id, *seat;
|
||||||
|
|
||||||
|
/* set device name */
|
||||||
|
dev->drm.name =
|
||||||
|
eina_stringshare_add(udev_device_get_devnode(tmpdevice));
|
||||||
|
|
||||||
|
/* set device path */
|
||||||
|
dev->drm.path =
|
||||||
|
eina_stringshare_add(udev_device_get_syspath(tmpdevice));
|
||||||
|
|
||||||
|
/* store id for this device */
|
||||||
|
if ((id = udev_device_get_sysnum(tmpdevice)))
|
||||||
|
dev->id = atoi(id);
|
||||||
|
|
||||||
|
/* set dev seat */
|
||||||
|
seat = udev_device_get_property_value(tmpdevice, "ID_SEAT");
|
||||||
|
if (!seat) seat = "seat0";
|
||||||
|
|
||||||
|
dev->seat = eina_stringshare_add(seat);
|
||||||
|
|
||||||
|
dev->format = GBM_FORMAT_XRGB8888;
|
||||||
|
dev->use_hw_accel = EINA_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release device reference */
|
||||||
|
udev_device_unref(tmpdevice);
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free an Ecore_Drm_Device
|
||||||
|
*
|
||||||
|
* This function will cleanup and free any previously allocated Ecore_Drm_Device.
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to free
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_device_free(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if (!dev) return;
|
||||||
|
|
||||||
|
/* free outputs */
|
||||||
|
EINA_LIST_FREE(dev->outputs, output)
|
||||||
|
ecore_drm_output_free(output);
|
||||||
|
|
||||||
|
/* free crtcs */
|
||||||
|
if (dev->crtcs) free(dev->crtcs);
|
||||||
|
|
||||||
|
/* free device name */
|
||||||
|
if (dev->drm.name) eina_stringshare_del(dev->drm.name);
|
||||||
|
|
||||||
|
/* free device path */
|
||||||
|
if (dev->drm.path) eina_stringshare_del(dev->drm.path);
|
||||||
|
|
||||||
|
/* free device seat */
|
||||||
|
if (dev->seat) eina_stringshare_del(dev->seat);
|
||||||
|
|
||||||
|
/* free structure */
|
||||||
|
free(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open an Ecore_Drm_Device
|
||||||
|
*
|
||||||
|
* This function will open an existing Ecore_Drm_Device for use.
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to try and open
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_device_open(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
uint64_t caps;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!dev->drm.name)) return EINA_FALSE;
|
||||||
|
|
||||||
|
dev->drm.fd = open(dev->drm.name, O_RDWR);
|
||||||
|
if (dev->drm.fd < 0) return EINA_FALSE;
|
||||||
|
|
||||||
|
DBG("Opened Device %s : %d", dev->drm.name, dev->drm.fd);
|
||||||
|
|
||||||
|
if (!drmGetCap(dev->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &caps))
|
||||||
|
{
|
||||||
|
if (caps == 1)
|
||||||
|
dev->drm.clock = CLOCK_MONOTONIC;
|
||||||
|
else
|
||||||
|
dev->drm.clock = CLOCK_REALTIME;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERR("Could not get device capabilities: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* if (getenv("ECORE_DRM_HW_ACCEL")) */
|
||||||
|
/* { */
|
||||||
|
/* Typically, gbm loads the dri driver However some versions of Mesa
|
||||||
|
* do not have libglapi symbols linked in the driver. Because of this,
|
||||||
|
* using hardware accel for our drm code Could fail with a
|
||||||
|
* message that the driver could not load. Let's be proactive and
|
||||||
|
* work around this for the user by preloading the glapi library */
|
||||||
|
/* dlopen("libglapi.so.0", (RTLD_LAZY | RTLD_GLOBAL)); */
|
||||||
|
|
||||||
|
/* if ((dev->gbm = gbm_create_device(dev->drm.fd))) */
|
||||||
|
/* { */
|
||||||
|
/* EGLint major, minor, visual; */
|
||||||
|
/* const EGLint attribs[] = */
|
||||||
|
/* { */
|
||||||
|
/* EGL_SURFACE_TYPE, EGL_WINDOW_BIT, */
|
||||||
|
/* EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, */
|
||||||
|
/* EGL_BLUE_SIZE, 1, EGL_ALPHA_SIZE, 0, */
|
||||||
|
/* EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE */
|
||||||
|
/* }; */
|
||||||
|
|
||||||
|
/* dev->use_hw_accel = EINA_TRUE; */
|
||||||
|
/* dev->format = GBM_FORMAT_XRGB8888; */
|
||||||
|
|
||||||
|
/* dev->egl.disp = eglGetDisplay(dev->gbm); */
|
||||||
|
/* if (dev->egl.disp == EGL_NO_DISPLAY) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not get egl display"); */
|
||||||
|
/* goto init_software; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (!eglInitialize(dev->egl.disp, &major, &minor)) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not initialize egl"); */
|
||||||
|
/* goto init_software; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* visual = dev->format; */
|
||||||
|
/* if (!_ecore_drm_device_egl_config_get(dev, attribs, &visual)) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not get egl config"); */
|
||||||
|
/* goto init_software; */
|
||||||
|
/* } */
|
||||||
|
/* } */
|
||||||
|
/* else */
|
||||||
|
/* { */
|
||||||
|
/* WRN("Failed to create gbm device"); */
|
||||||
|
/* goto init_software; */
|
||||||
|
/* } */
|
||||||
|
/* } */
|
||||||
|
/* else */
|
||||||
|
/* #endif */
|
||||||
|
/* { */
|
||||||
|
/* TODO: init software */
|
||||||
|
/* init_software: */
|
||||||
|
/* DBG("Init Software Engine"); */
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* if (dev->egl.disp) */
|
||||||
|
/* { */
|
||||||
|
/* eglMakeCurrent(dev->egl.disp, EGL_NO_SURFACE, EGL_NO_SURFACE, */
|
||||||
|
/* EGL_NO_CONTEXT); */
|
||||||
|
/* eglTerminate(dev->egl.disp); */
|
||||||
|
/* eglReleaseThread(); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (dev->gbm) gbm_device_destroy(dev->gbm); */
|
||||||
|
/* dev->gbm = NULL; */
|
||||||
|
/* #endif */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
dev->drm.hdlr =
|
||||||
|
ecore_main_fd_handler_add(dev->drm.fd, ECORE_FD_READ,
|
||||||
|
_ecore_drm_device_cb_event, dev, NULL, NULL);
|
||||||
|
|
||||||
|
dev->drm.idler =
|
||||||
|
ecore_idle_enterer_add(_ecore_drm_device_cb_idle, dev);
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close an Ecore_Drm_Device
|
||||||
|
*
|
||||||
|
* This function will close a previously opened Ecore_Drm_Device
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to free
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_device_close(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
/* check for valid device */
|
||||||
|
if (!dev) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* if (dev->use_hw_accel) */
|
||||||
|
/* { */
|
||||||
|
/* if (dev->egl.disp) */
|
||||||
|
/* { */
|
||||||
|
/* eglMakeCurrent(dev->egl.disp, EGL_NO_SURFACE, EGL_NO_SURFACE, */
|
||||||
|
/* EGL_NO_CONTEXT); */
|
||||||
|
/* eglTerminate(dev->egl.disp); */
|
||||||
|
/* eglReleaseThread(); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (dev->gbm) gbm_device_destroy(dev->gbm); */
|
||||||
|
/* dev->gbm = NULL; */
|
||||||
|
/* } */
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
if (dev->drm.hdlr) ecore_main_fd_handler_del(dev->drm.hdlr);
|
||||||
|
dev->drm.hdlr = NULL;
|
||||||
|
|
||||||
|
close(dev->drm.fd);
|
||||||
|
|
||||||
|
/* reset device fd */
|
||||||
|
dev->drm.fd = -1;
|
||||||
|
|
||||||
|
/* free(data); */
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get if a given Ecore_Drm_Device is master
|
||||||
|
*
|
||||||
|
* This function will check if the given drm device is set to master
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to check
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE if device is master, EINA_FALSE otherwise
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_device_master_get(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
/* drm_magic_t mag; */
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* FIXME: Remote this to the slave process !! */
|
||||||
|
|
||||||
|
/* get if we are master or not */
|
||||||
|
/* if ((drmGetMagic(dev->drm.fd, &mag) == 0) && */
|
||||||
|
/* (drmAuthMagic(dev->drm.fd, mag) == 0)) */
|
||||||
|
/* return EINA_TRUE; */
|
||||||
|
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a given Ecore_Drm_Device to master
|
||||||
|
*
|
||||||
|
* This function will attempt to set a given drm device to be master
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to set
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_device_master_set(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Eina_Bool ret = EINA_FALSE;
|
||||||
|
int dfd;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
DBG("Set Master On Fd: %d", dev->drm.fd);
|
||||||
|
|
||||||
|
/* try to close the device */
|
||||||
|
_ecore_drm_message_send(ECORE_DRM_OP_DEVICE_MASTER_SET, dev->drm.fd,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
|
/* get the result of the close operation */
|
||||||
|
ret = _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_MASTER_SET, &dfd,
|
||||||
|
NULL, 0);
|
||||||
|
if (!ret) return EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell a given Ecore_Drm_Device to stop being master
|
||||||
|
*
|
||||||
|
* This function will attempt to ask a drm device to stop being master
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device to set
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Device_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_device_master_drop(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Eina_Bool ret = EINA_FALSE;
|
||||||
|
int dfd;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
DBG("Drop Master On Fd: %d", dev->drm.fd);
|
||||||
|
|
||||||
|
/* try to close the device */
|
||||||
|
_ecore_drm_message_send(ECORE_DRM_OP_DEVICE_MASTER_DROP, dev->drm.fd,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
|
/* get the result of the close operation */
|
||||||
|
ret = _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_MASTER_DROP, &dfd,
|
||||||
|
NULL, 0);
|
||||||
|
if (!ret) return EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI int
|
||||||
|
ecore_drm_device_fd_get(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
if (!dev) return -1;
|
||||||
|
return dev->drm.fd;
|
||||||
|
}
|
|
@ -0,0 +1,360 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* copied from udev/extras/input_id/input_id.c */
|
||||||
|
/* we must use this kernel-compatible implementation */
|
||||||
|
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
||||||
|
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
|
||||||
|
#define OFF(x) ((x)%BITS_PER_LONG)
|
||||||
|
#define BIT(x) (1UL<<OFF(x))
|
||||||
|
#define LONG(x) ((x)/BITS_PER_LONG)
|
||||||
|
#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
|
||||||
|
/* end copied */
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
|
||||||
|
/* local functions */
|
||||||
|
static Eina_Bool
|
||||||
|
_device_configure(Ecore_Drm_Evdev *edev)
|
||||||
|
{
|
||||||
|
Eina_Bool ret = EINA_FALSE;
|
||||||
|
|
||||||
|
if (!edev) return EINA_FALSE;
|
||||||
|
|
||||||
|
if ((edev->caps & (EVDEV_MOTION_ABS | EVDEV_MOTION_REL)) &&
|
||||||
|
(edev->caps & EVDEV_BUTTON))
|
||||||
|
{
|
||||||
|
DBG("Input device %s is a pointer", edev->name);
|
||||||
|
edev->seat_caps |= EVDEV_SEAT_POINTER;
|
||||||
|
ret = EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edev->caps & EVDEV_KEYBOARD)
|
||||||
|
{
|
||||||
|
DBG("Input device %s is a keyboard", edev->name);
|
||||||
|
edev->seat_caps |= EVDEV_SEAT_KEYBOARD;
|
||||||
|
ret = EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edev->caps & EVDEV_TOUCH)
|
||||||
|
{
|
||||||
|
DBG("Input device %s is a touchpad", edev->name);
|
||||||
|
edev->seat_caps |= EVDEV_SEAT_TOUCH;
|
||||||
|
ret = EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_device_handle(Ecore_Drm_Evdev *edev)
|
||||||
|
{
|
||||||
|
struct input_absinfo absinfo;
|
||||||
|
unsigned long dev_bits[NBITS(EV_MAX)];
|
||||||
|
unsigned long abs_bits[NBITS(ABS_MAX)];
|
||||||
|
unsigned long rel_bits[NBITS(REL_MAX)];
|
||||||
|
unsigned long key_bits[NBITS(KEY_MAX)];
|
||||||
|
/* Eina_Bool have_key = EINA_FALSE; */
|
||||||
|
Eina_Bool have_abs = EINA_FALSE;
|
||||||
|
|
||||||
|
if (!edev) return EINA_FALSE;
|
||||||
|
|
||||||
|
ioctl(edev->fd, EVIOCGBIT(0, sizeof(dev_bits)), dev_bits);
|
||||||
|
if (TEST_BIT(dev_bits, EV_ABS))
|
||||||
|
{
|
||||||
|
have_abs = EINA_TRUE;
|
||||||
|
|
||||||
|
ioctl(edev->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
|
||||||
|
|
||||||
|
if ((TEST_BIT(abs_bits, ABS_WHEEL)) ||
|
||||||
|
(TEST_BIT(abs_bits, ABS_GAS)) ||
|
||||||
|
(TEST_BIT(abs_bits, ABS_BRAKE)) ||
|
||||||
|
(TEST_BIT(abs_bits, ABS_HAT0X)))
|
||||||
|
{
|
||||||
|
/* ignore joystick */
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(abs_bits, ABS_X))
|
||||||
|
{
|
||||||
|
ioctl(edev->fd, EVIOCGABS(ABS_X), &absinfo);
|
||||||
|
edev->abs.min_x = absinfo.minimum;
|
||||||
|
edev->abs.max_x = absinfo.maximum;
|
||||||
|
edev->caps |= EVDEV_MOTION_ABS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(abs_bits, ABS_Y))
|
||||||
|
{
|
||||||
|
ioctl(edev->fd, EVIOCGABS(ABS_Y), &absinfo);
|
||||||
|
edev->abs.min_y = absinfo.minimum;
|
||||||
|
edev->abs.max_y = absinfo.maximum;
|
||||||
|
edev->caps |= EVDEV_MOTION_ABS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((TEST_BIT(abs_bits, ABS_MT_POSITION_X)) &&
|
||||||
|
(TEST_BIT(abs_bits, ABS_MT_POSITION_Y)))
|
||||||
|
{
|
||||||
|
DBG("Handle MultiTouch Device: %s", edev->path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(dev_bits, EV_REL))
|
||||||
|
{
|
||||||
|
ioctl(edev->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits);
|
||||||
|
|
||||||
|
if ((TEST_BIT(rel_bits, REL_X)) || (TEST_BIT(rel_bits, REL_Y)))
|
||||||
|
edev->caps |= EVDEV_MOTION_REL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(dev_bits, EV_KEY))
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
/* have_key = EINA_TRUE; */
|
||||||
|
|
||||||
|
ioctl(edev->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits);
|
||||||
|
|
||||||
|
if (have_abs)
|
||||||
|
{
|
||||||
|
if ((TEST_BIT(key_bits, BTN_TOOL_FINGER)) &&
|
||||||
|
(!TEST_BIT(key_bits, BTN_TOOL_PEN)))
|
||||||
|
{
|
||||||
|
DBG("Device Is Touchpad: %s", edev->path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = KEY_ESC; i < KEY_MAX; i++)
|
||||||
|
{
|
||||||
|
if ((i >= BTN_MISC) && (i < KEY_OK)) continue;
|
||||||
|
if (TEST_BIT(key_bits, i))
|
||||||
|
{
|
||||||
|
edev->caps |= EVDEV_KEYBOARD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(key_bits, BTN_TOUCH))
|
||||||
|
edev->caps |= EVDEV_TOUCH;
|
||||||
|
|
||||||
|
for (i = BTN_MISC; i < BTN_JOYSTICK; i++)
|
||||||
|
{
|
||||||
|
if (TEST_BIT(key_bits, i))
|
||||||
|
{
|
||||||
|
edev->caps |= EVDEV_BUTTON;
|
||||||
|
edev->caps &= ~EVDEV_TOUCH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEST_BIT(dev_bits, EV_LED)) edev->caps |= EVDEV_KEYBOARD;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_device_notify_key(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
|
||||||
|
{
|
||||||
|
DBG("Key Event");
|
||||||
|
DBG("\tCode: %d", event->code);
|
||||||
|
DBG("\tValue: %d", event->value);
|
||||||
|
|
||||||
|
if ((event->code >= KEY_ESC) && (event->code <= KEY_COMPOSE))
|
||||||
|
{
|
||||||
|
/* ignore key repeat */
|
||||||
|
if (event->value == 2)
|
||||||
|
{
|
||||||
|
DBG("\tKey Repeat");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_device_process_flush(Ecore_Drm_Evdev *dev, unsigned int timestamp)
|
||||||
|
{
|
||||||
|
switch (dev->pending_event)
|
||||||
|
{
|
||||||
|
case EVDEV_NONE:
|
||||||
|
return;
|
||||||
|
case EVDEV_RELATIVE_MOTION:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_MT_DOWN:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_MT_MOTION:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_MT_UP:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_TOUCH_DOWN:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_MOTION:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case EVDEV_ABSOLUTE_TOUCH_UP:
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
dev->pending_event = EVDEV_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_device_process_key(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
|
||||||
|
{
|
||||||
|
if (event->code == BTN_TOUCH)
|
||||||
|
{
|
||||||
|
/* TODO: check for mt device */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_device_process_flush(dev, timestamp);
|
||||||
|
|
||||||
|
switch (event->code)
|
||||||
|
{
|
||||||
|
case BTN_LEFT:
|
||||||
|
case BTN_RIGHT:
|
||||||
|
case BTN_MIDDLE:
|
||||||
|
case BTN_SIDE:
|
||||||
|
case BTN_EXTRA:
|
||||||
|
case BTN_FORWARD:
|
||||||
|
case BTN_BACK:
|
||||||
|
case BTN_TASK:
|
||||||
|
/* TODO: notify button */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_device_notify_key(dev, event, timestamp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_device_process(Ecore_Drm_Evdev *dev, struct input_event *event, int count)
|
||||||
|
{
|
||||||
|
struct input_event *ev, *end;
|
||||||
|
unsigned int timestamp = 0;
|
||||||
|
|
||||||
|
DBG("Evdev Device Process");
|
||||||
|
|
||||||
|
ev = event;
|
||||||
|
end = ev + count;
|
||||||
|
for (ev = event; ev < end; ev++)
|
||||||
|
{
|
||||||
|
timestamp = (ev->time.tv_sec * 1000) + (ev->time.tv_usec / 1000);
|
||||||
|
|
||||||
|
switch (ev->type)
|
||||||
|
{
|
||||||
|
case EV_KEY:
|
||||||
|
_device_process_key(dev, ev, timestamp);
|
||||||
|
break;
|
||||||
|
case EV_REL:
|
||||||
|
DBG("\tRelative Event");
|
||||||
|
break;
|
||||||
|
case EV_ABS:
|
||||||
|
DBG("\tAbsolute Event");
|
||||||
|
break;
|
||||||
|
case EV_SYN:
|
||||||
|
_device_process_flush(dev, timestamp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_cb_device_data(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Evdev *edev;
|
||||||
|
struct input_event ev[32];
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (!(edev = data)) return EINA_TRUE;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
len = read(edev->fd, &ev, sizeof(ev));
|
||||||
|
|
||||||
|
if ((len < 0) || ((len % sizeof(ev[0])) != 0))
|
||||||
|
{
|
||||||
|
if ((len < 0) && (errno != EAGAIN) && (errno != EINTR))
|
||||||
|
{
|
||||||
|
ERR("Device Died");
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
edev->event_process(edev, ev, (len / sizeof(ev[0])));
|
||||||
|
|
||||||
|
} while (len > 0);
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* external functions */
|
||||||
|
Ecore_Drm_Evdev *
|
||||||
|
_ecore_drm_evdev_device_create(Ecore_Drm_Seat *seat, const char *path, int fd)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Evdev *edev;
|
||||||
|
char name[256] = "unknown";
|
||||||
|
|
||||||
|
if (!(edev = calloc(1, sizeof(Ecore_Drm_Evdev))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
edev->seat = seat;
|
||||||
|
edev->path = eina_stringshare_add(path);
|
||||||
|
edev->fd = fd;
|
||||||
|
|
||||||
|
if (ioctl(edev->fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
||||||
|
DBG("Error getting device name: %m");
|
||||||
|
|
||||||
|
name[sizeof(name) - 1] = '\0';
|
||||||
|
edev->name = eina_stringshare_add(name);
|
||||||
|
|
||||||
|
if (!_device_handle(edev))
|
||||||
|
{
|
||||||
|
ERR("Unhandled Input Device: %s", name);
|
||||||
|
_ecore_drm_evdev_device_destroy(edev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_device_configure(edev))
|
||||||
|
{
|
||||||
|
_ecore_drm_evdev_device_destroy(edev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
edev->event_process = _device_process;
|
||||||
|
|
||||||
|
edev->hdlr =
|
||||||
|
ecore_main_fd_handler_add(edev->fd, ECORE_FD_READ,
|
||||||
|
_cb_device_data, edev, NULL, NULL);
|
||||||
|
if (!edev->hdlr)
|
||||||
|
{
|
||||||
|
ERR("Could not create fd handler");
|
||||||
|
_ecore_drm_evdev_device_destroy(edev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return edev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_ecore_drm_evdev_device_destroy(Ecore_Drm_Evdev *dev)
|
||||||
|
{
|
||||||
|
if (!dev) return;
|
||||||
|
|
||||||
|
if (dev->path) eina_stringshare_del(dev->path);
|
||||||
|
if (dev->name) eina_stringshare_del(dev->name);
|
||||||
|
if (dev->hdlr) ecore_main_fd_handler_del(dev->hdlr);
|
||||||
|
|
||||||
|
free(dev);
|
||||||
|
}
|
|
@ -0,0 +1,151 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Fb_Group
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO: DOXY !! */
|
||||||
|
|
||||||
|
EAPI Ecore_Drm_Fb *
|
||||||
|
ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Fb *fb;
|
||||||
|
struct drm_mode_create_dumb carg;
|
||||||
|
struct drm_mode_destroy_dumb darg;
|
||||||
|
struct drm_mode_map_dumb marg;
|
||||||
|
|
||||||
|
if (!(fb = calloc(1, sizeof(Ecore_Drm_Fb)))) return NULL;
|
||||||
|
|
||||||
|
memset(&carg, 0, sizeof(struct drm_mode_create_dumb));
|
||||||
|
|
||||||
|
carg.bpp = 32; // FIXME: Hard-coded depth
|
||||||
|
carg.width = width;
|
||||||
|
carg.height = height;
|
||||||
|
|
||||||
|
if (drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg))
|
||||||
|
{
|
||||||
|
ERR("Could not create dumb framebuffer: %m");
|
||||||
|
goto create_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb->from_client = EINA_TRUE;
|
||||||
|
fb->hdl = carg.handle;
|
||||||
|
fb->stride = carg.pitch;
|
||||||
|
fb->size = carg.size;
|
||||||
|
fb->fd = dev->drm.fd;
|
||||||
|
|
||||||
|
if (drmModeAddFB(dev->drm.fd, width, height, 24, 32,
|
||||||
|
fb->stride, fb->hdl, &fb->id))
|
||||||
|
{
|
||||||
|
ERR("Could not add framebuffer: %m");
|
||||||
|
goto add_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&marg, 0, sizeof(struct drm_mode_map_dumb));
|
||||||
|
marg.handle = fb->hdl;
|
||||||
|
if (drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_MAP_DUMB, &marg))
|
||||||
|
{
|
||||||
|
ERR("Could not map framebuffer: %m");
|
||||||
|
goto map_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb->mmap =
|
||||||
|
mmap(0, fb->size, PROT_WRITE | PROT_READ, MAP_SHARED,
|
||||||
|
dev->drm.fd, marg.offset);
|
||||||
|
if (fb->mmap == MAP_FAILED)
|
||||||
|
{
|
||||||
|
ERR("Could not mmap framebuffer space: %m");
|
||||||
|
goto map_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(fb->mmap, 0, fb->size);
|
||||||
|
|
||||||
|
return fb;
|
||||||
|
|
||||||
|
map_err:
|
||||||
|
drmModeRmFB(fb->fd, fb->id);
|
||||||
|
add_err:
|
||||||
|
memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
|
||||||
|
darg.handle = fb->hdl;
|
||||||
|
drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
|
||||||
|
create_err:
|
||||||
|
free(fb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_fb_destroy(Ecore_Drm_Fb *fb)
|
||||||
|
{
|
||||||
|
struct drm_mode_destroy_dumb darg;
|
||||||
|
|
||||||
|
if ((!fb) || (!fb->mmap)) return;
|
||||||
|
|
||||||
|
if (fb->id) drmModeRmFB(fb->fd, fb->id);
|
||||||
|
munmap(fb->mmap, fb->size);
|
||||||
|
memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
|
||||||
|
darg.handle = fb->hdl;
|
||||||
|
drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
|
||||||
|
free(fb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* static void */
|
||||||
|
/* _ecore_drm_fb_user_data_destroy(struct gbm_bo *bo EINA_UNUSED, void *data) */
|
||||||
|
/* { */
|
||||||
|
/* Ecore_Drm_Fb *fb; */
|
||||||
|
|
||||||
|
/* if (!(fb = data)) return; */
|
||||||
|
/* ecore_drm_fb_destroy(fb); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* Ecore_Drm_Fb * */
|
||||||
|
/* _ecore_drm_fb_bo_get(Ecore_Drm_Device *dev, struct gbm_bo *bo) */
|
||||||
|
/* { */
|
||||||
|
/* Ecore_Drm_Fb *fb; */
|
||||||
|
/* unsigned int width, height; */
|
||||||
|
/* unsigned int h[4], p[4], o[4]; */
|
||||||
|
/* int ret = -1; */
|
||||||
|
|
||||||
|
/* if ((fb = gbm_bo_get_user_data(bo))) return fb; */
|
||||||
|
|
||||||
|
/* if (!(fb = calloc(1, sizeof(Ecore_Drm_Fb)))) return NULL; */
|
||||||
|
|
||||||
|
/* fb->bo = bo; */
|
||||||
|
|
||||||
|
/* width = gbm_bo_get_width(bo); */
|
||||||
|
/* height = gbm_bo_get_height(bo); */
|
||||||
|
/* fb->stride = gbm_bo_get_stride(bo); */
|
||||||
|
/* fb->hdl = gbm_bo_get_handle(bo).u32; */
|
||||||
|
/* fb->size = (fb->stride * height); */
|
||||||
|
/* fb->fd = dev->drm.fd; */
|
||||||
|
|
||||||
|
/* h[0] = fb->hdl; */
|
||||||
|
/* p[0] = fb->stride; */
|
||||||
|
/* o[0] = 0; */
|
||||||
|
|
||||||
|
/* ret = drmModeAddFB2(dev->drm.fd, width, height, dev->format, h, p, o, */
|
||||||
|
/* &fb->id, 0); */
|
||||||
|
/* if (ret) */
|
||||||
|
/* { */
|
||||||
|
/* ret = drmModeAddFB(dev->drm.fd, width, height, 24, 32, */
|
||||||
|
/* fb->stride, fb->hdl, &fb->id); */
|
||||||
|
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (ret) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Error during ModeAddFb"); */
|
||||||
|
/* free(fb); */
|
||||||
|
/* return NULL; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* gbm_bo_set_user_data(bo, fb, _ecore_drm_fb_user_data_destroy); */
|
||||||
|
|
||||||
|
/* return fb; */
|
||||||
|
/* } */
|
||||||
|
/* #endif */
|
|
@ -0,0 +1,303 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
|
||||||
|
/* local functions */
|
||||||
|
static Ecore_Drm_Seat *
|
||||||
|
_seat_get(Ecore_Drm_Input *input, const char *seat)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Seat *s;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(input->dev->seats, l, s)
|
||||||
|
{
|
||||||
|
if (!strcmp(s->name, seat)) return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(s = calloc(1, sizeof(Ecore_Drm_Seat))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
s->input = input;
|
||||||
|
s->name = eina_stringshare_add(seat);
|
||||||
|
|
||||||
|
input->dev->seats = eina_list_append(input->dev->seats, s);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_device_add(Ecore_Drm_Input *input, struct udev_device *device)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Evdev *edev;
|
||||||
|
Ecore_Drm_Seat *seat;
|
||||||
|
const char *dev_seat, *wl_seat;
|
||||||
|
const char *node;
|
||||||
|
char n[PATH_MAX];
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
if (!(dev_seat = udev_device_get_property_value(device, "ID_SEAT")))
|
||||||
|
dev_seat = "seat0";
|
||||||
|
|
||||||
|
if (strcmp(dev_seat, input->seat)) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (!(wl_seat = udev_device_get_property_value(device, "WL_SEAT")))
|
||||||
|
wl_seat = "seat0";
|
||||||
|
|
||||||
|
if (!(seat = _seat_get(input, wl_seat)))
|
||||||
|
return EINA_FALSE;
|
||||||
|
|
||||||
|
node = udev_device_get_devnode(device);
|
||||||
|
strcpy(n, node);
|
||||||
|
fd = open(n, O_RDWR | O_NONBLOCK);
|
||||||
|
/* _ecore_drm_message_send(ECORE_DRM_OP_DEVICE_OPEN, -1, n, strlen(n)); */
|
||||||
|
/* _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_OPEN, &fd, NULL, 0); */
|
||||||
|
/* DBG("Opened Restricted Input: %s %d", node, fd); */
|
||||||
|
|
||||||
|
if (!(edev = _ecore_drm_evdev_device_create(seat, node, fd)))
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
/* _ecore_drm_message_send(ECORE_DRM_OP_DEVICE_CLOSE, fd, NULL, 0); */
|
||||||
|
/* _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_OPEN, &fd, NULL, 0); */
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
seat->devices = eina_list_append(seat->devices, edev);
|
||||||
|
|
||||||
|
/* TODO: finish */
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_device_remove(Ecore_Drm_Input *input, const char *device)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Seat *seat;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
if (!input) return;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(input->dev->seats, l, seat)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Evdev *edev;
|
||||||
|
Eina_List *ll;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(seat->devices, ll, edev)
|
||||||
|
{
|
||||||
|
if (!strcmp(edev->path, device))
|
||||||
|
{
|
||||||
|
seat->devices = eina_list_remove(seat->devices, edev);
|
||||||
|
_ecore_drm_evdev_device_destroy(edev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_cb_input_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Input *input;
|
||||||
|
struct udev_device *udevice;
|
||||||
|
const char *act;
|
||||||
|
|
||||||
|
DBG("Input Event");
|
||||||
|
|
||||||
|
if (!(input = data)) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (!(udevice = udev_monitor_receive_device(input->monitor)))
|
||||||
|
return EINA_TRUE;
|
||||||
|
|
||||||
|
if (!(act = udev_device_get_action(udevice))) return EINA_TRUE;
|
||||||
|
|
||||||
|
if (strncmp("event", udev_device_get_sysname(udevice), 5) != 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (!strcmp(act, "add"))
|
||||||
|
{
|
||||||
|
DBG("\tDevice Added");
|
||||||
|
_device_add(input, udevice);
|
||||||
|
}
|
||||||
|
else if (!strcmp(act, "remove"))
|
||||||
|
{
|
||||||
|
const char *node;
|
||||||
|
|
||||||
|
node = udev_device_get_devnode(udevice);
|
||||||
|
|
||||||
|
DBG("\tDevice Removed: %s", node);
|
||||||
|
_device_remove(input, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (udevice) udev_device_unref(udevice);
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_devices_add(Ecore_Drm_Input *input)
|
||||||
|
{
|
||||||
|
struct udev_enumerate *uenum;
|
||||||
|
struct udev_list_entry *uentry;
|
||||||
|
struct udev_device *udevice;
|
||||||
|
const char *path, *name;
|
||||||
|
Eina_Bool found = EINA_FALSE;
|
||||||
|
|
||||||
|
uenum = udev_enumerate_new(udev);
|
||||||
|
udev_enumerate_add_match_subsystem(uenum, "input");
|
||||||
|
udev_enumerate_scan_devices(uenum);
|
||||||
|
|
||||||
|
udev_list_entry_foreach(uentry, udev_enumerate_get_list_entry(uenum))
|
||||||
|
{
|
||||||
|
path = udev_list_entry_get_name(uentry);
|
||||||
|
udevice = udev_device_new_from_syspath(udev, path);
|
||||||
|
name = udev_device_get_sysname(udevice);
|
||||||
|
|
||||||
|
if (strncmp("event", name, 5) != 0)
|
||||||
|
{
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_device_add(input, udevice))
|
||||||
|
{
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = EINA_TRUE;
|
||||||
|
|
||||||
|
udev_device_unref(udevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
udev_enumerate_unref(uenum);
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
ERR("No Input Devices Found");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public functions */
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_inputs_create(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Input *input;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!udev)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* try to allocate space for input structure */
|
||||||
|
if (!(input = calloc(1, sizeof(Ecore_Drm_Input))))
|
||||||
|
return EINA_FALSE;
|
||||||
|
|
||||||
|
/* FIXME: Hardcoded seat name */
|
||||||
|
input->seat = eina_stringshare_add("seat0");
|
||||||
|
input->dev = dev;
|
||||||
|
|
||||||
|
/* try to enable this input */
|
||||||
|
if (!ecore_drm_inputs_enable(input))
|
||||||
|
{
|
||||||
|
ERR("Could not enable input");
|
||||||
|
if (input->seat) eina_stringshare_del(input->seat);
|
||||||
|
free(input);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add this input to dev */
|
||||||
|
dev->inputs = eina_list_append(dev->inputs, input);
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_inputs_destroy(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Seat *seat;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
if (!dev) return;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(dev->seats, l, seat)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Evdev *edev;
|
||||||
|
|
||||||
|
EINA_LIST_FREE(seat->devices, edev)
|
||||||
|
_ecore_drm_evdev_device_destroy(edev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_inputs_enable(Ecore_Drm_Input *input)
|
||||||
|
{
|
||||||
|
/* check for valid input */
|
||||||
|
if (!input) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (!input->monitor)
|
||||||
|
input->monitor = udev_monitor_new_from_netlink(udev, "udev");
|
||||||
|
|
||||||
|
if (!input->monitor)
|
||||||
|
{
|
||||||
|
ERR("Could not create udev monitor: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup input filter */
|
||||||
|
udev_monitor_filter_add_match_subsystem_devtype(input->monitor,
|
||||||
|
"input", NULL);
|
||||||
|
|
||||||
|
/* try to enable receiving udev events */
|
||||||
|
if (udev_monitor_enable_receiving(input->monitor))
|
||||||
|
{
|
||||||
|
ERR("Could not bind udev monitor: %m");
|
||||||
|
udev_monitor_unref(input->monitor);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save the fd */
|
||||||
|
if ((input->fd = udev_monitor_get_fd(input->monitor)) < 0)
|
||||||
|
{
|
||||||
|
ERR("Input monitor has no fd: %m");
|
||||||
|
udev_monitor_unref(input->monitor);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create fd handler */
|
||||||
|
if (!input->hdlr)
|
||||||
|
{
|
||||||
|
input->hdlr =
|
||||||
|
ecore_main_fd_handler_add(input->fd, ECORE_FD_READ,
|
||||||
|
_cb_input_event, input, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input->hdlr)
|
||||||
|
{
|
||||||
|
ERR("Failed to setup input fd handler: %m");
|
||||||
|
udev_monitor_unref(input->monitor);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to add devices */
|
||||||
|
if (!_devices_add(input))
|
||||||
|
{
|
||||||
|
ERR("Could not add input devices");
|
||||||
|
udev_monitor_unref(input->monitor);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
input->enabled = EINA_TRUE;
|
||||||
|
input->suspended = EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_inputs_disable(Ecore_Drm_Input *input)
|
||||||
|
{
|
||||||
|
if (!input) return;
|
||||||
|
}
|
|
@ -0,0 +1,703 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
|
||||||
|
#define ALEN(array) (sizeof(array) / sizeof(array)[0])
|
||||||
|
|
||||||
|
static const char *conn_types[] =
|
||||||
|
{
|
||||||
|
"None", "VGA", "DVI", "DVI", "DVI",
|
||||||
|
"Composite", "TV", "LVDS", "CTV", "DIN",
|
||||||
|
"DP", "HDMI", "HDMI", "TV", "eDP",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* local functions */
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* static Eina_Bool */
|
||||||
|
/* _ecore_drm_output_context_create(Ecore_Drm_Device *dev, EGLSurface surface) */
|
||||||
|
/* { */
|
||||||
|
/* EGLBoolean r; */
|
||||||
|
/* static const EGLint attribs[] = */
|
||||||
|
/* { */
|
||||||
|
/* EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE */
|
||||||
|
/* }; */
|
||||||
|
|
||||||
|
/* if ((!dev->egl.disp) || (!dev->egl.cfg)) return EINA_FALSE; */
|
||||||
|
|
||||||
|
/* if (!eglBindAPI(EGL_OPENGL_ES_API)) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not bind egl api"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* dev->egl.ctxt = */
|
||||||
|
/* eglCreateContext(dev->egl.disp, dev->egl.cfg, EGL_NO_CONTEXT, attribs); */
|
||||||
|
/* if (!dev->egl.ctxt) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not create Egl Context"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* r = eglMakeCurrent(dev->egl.disp, surface, surface, dev->egl.ctxt); */
|
||||||
|
/* if (r == EGL_FALSE) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not make surface current"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* return EINA_TRUE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* static Eina_Bool */
|
||||||
|
/* _ecore_drm_output_hardware_setup(Ecore_Drm_Device *dev, Ecore_Drm_Output *output) */
|
||||||
|
/* { */
|
||||||
|
/* unsigned int i = 0; */
|
||||||
|
/* int flags = 0; */
|
||||||
|
/* int w = 0, h = 0; */
|
||||||
|
|
||||||
|
/* if ((!dev) || (!output)) return EINA_FALSE; */
|
||||||
|
|
||||||
|
/* if (output->current_mode) */
|
||||||
|
/* { */
|
||||||
|
/* w = output->current_mode->width; */
|
||||||
|
/* h = output->current_mode->height; */
|
||||||
|
/* } */
|
||||||
|
/* else */
|
||||||
|
/* { */
|
||||||
|
/* w = 1024; */
|
||||||
|
/* h = 768; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* flags = (GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); */
|
||||||
|
|
||||||
|
/* if (!(output->surface = */
|
||||||
|
/* gbm_surface_create(dev->gbm, w, h, GBM_FORMAT_ARGB8888, flags))) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not create output surface"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (!(output->egl.surface = */
|
||||||
|
/* eglCreateWindowSurface(dev->egl.disp, dev->egl.cfg, */
|
||||||
|
/* output->surface, NULL))) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not create output egl surface"); */
|
||||||
|
/* gbm_surface_destroy(output->surface); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (!dev->egl.ctxt) */
|
||||||
|
/* { */
|
||||||
|
/* if (!_ecore_drm_output_context_create(dev, output->egl.surface)) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not create context"); */
|
||||||
|
/* gbm_surface_destroy(output->surface); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* flags = (GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE); */
|
||||||
|
/* for (i = 0; i < NUM_FRAME_BUFFERS; i++) */
|
||||||
|
/* { */
|
||||||
|
/* if (output->cursor[i]) continue; */
|
||||||
|
/* if (!(output->cursor[i] = */
|
||||||
|
/* gbm_bo_create(dev->gbm, 64, 64, dev->format, flags))) */
|
||||||
|
/* { */
|
||||||
|
/* continue; */
|
||||||
|
/* } */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if ((!output->cursor[0]) || (!output->cursor[1])) */
|
||||||
|
/* { */
|
||||||
|
/* WRN("Hardware Cursor Buffers not available"); */
|
||||||
|
/* dev->cursors_broken = EINA_TRUE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* return EINA_TRUE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* static void */
|
||||||
|
/* _ecore_drm_output_hardware_render(Ecore_Drm_Output *output) */
|
||||||
|
/* { */
|
||||||
|
/* struct gbm_bo *bo; */
|
||||||
|
/* int ret; */
|
||||||
|
|
||||||
|
/* if (!output) return; */
|
||||||
|
/* if (!output->current_mode) return; */
|
||||||
|
|
||||||
|
/* glViewport(output->x, output->y, */
|
||||||
|
/* output->current_mode->width, output->current_mode->height); */
|
||||||
|
|
||||||
|
/* if (eglMakeCurrent(output->dev->egl.disp, output->egl.surface, */
|
||||||
|
/* output->egl.surface, output->dev->egl.ctxt) == EGL_FALSE) */
|
||||||
|
/* return; */
|
||||||
|
|
||||||
|
/* glClearColor(1.0, 1.0, 0.0, 1.0); */
|
||||||
|
/* glClear(GL_COLOR_BUFFER_BIT); */
|
||||||
|
/* glFlush(); */
|
||||||
|
|
||||||
|
/* eglSwapBuffers(output->dev->egl.disp, output->egl.surface); */
|
||||||
|
|
||||||
|
/* if (!(bo = gbm_surface_lock_front_buffer(output->surface))) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Failed to lock front buffer"); */
|
||||||
|
/* return; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (!(output->next = _ecore_drm_fb_bo_get(output->dev, bo))) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Failed to get FB from bo"); */
|
||||||
|
/* gbm_surface_release_buffer(output->surface, bo); */
|
||||||
|
/* } */
|
||||||
|
/* } */
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_output_software_setup(Ecore_Drm_Device *dev, Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
int w = 0, h = 0;
|
||||||
|
|
||||||
|
if ((!dev) || (!output)) return EINA_FALSE;
|
||||||
|
|
||||||
|
if (output->current_mode)
|
||||||
|
{
|
||||||
|
w = output->current_mode->width;
|
||||||
|
h = output->current_mode->height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
w = 1024;
|
||||||
|
h = 768;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_FRAME_BUFFERS; i++)
|
||||||
|
{
|
||||||
|
if (!(output->dumb[i] = ecore_drm_fb_create(dev, w, h)))
|
||||||
|
{
|
||||||
|
ERR("Could not create dumb framebuffer %d", i);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
|
||||||
|
err:
|
||||||
|
for (i = 0; i < NUM_FRAME_BUFFERS; i++)
|
||||||
|
{
|
||||||
|
if (output->dumb[i]) ecore_drm_fb_destroy(output->dumb[i]);
|
||||||
|
output->dumb[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_ecore_drm_output_software_render(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
if (!output) return;
|
||||||
|
if (!output->current_mode) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_ecore_drm_output_crtc_find(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnector *conn)
|
||||||
|
{
|
||||||
|
drmModeEncoder *enc;
|
||||||
|
unsigned int p;
|
||||||
|
int i = 0, j = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < conn->count_encoders; j++)
|
||||||
|
{
|
||||||
|
/* get the encoder on this connector */
|
||||||
|
if (!(enc = drmModeGetEncoder(dev->drm.fd, conn->encoders[j])))
|
||||||
|
{
|
||||||
|
ERR("Failed to get encoder: %m");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = enc->possible_crtcs;
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
|
||||||
|
for (i = 0; i < res->count_crtcs; i++)
|
||||||
|
{
|
||||||
|
if ((p & (1 << i)) &&
|
||||||
|
(!(dev->crtc_allocator & (1 << res->crtcs[i]))))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* DBG("Added Mode: %dx%d@%d to Output %d", */
|
||||||
|
/* mode->width, mode->height, mode->refresh, output->crtc_id); */
|
||||||
|
|
||||||
|
output->modes = eina_list_append(output->modes, mode);
|
||||||
|
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ecore_Drm_Output *
|
||||||
|
_ecore_drm_output_create(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnector *conn, int x, int y)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
Ecore_Drm_Output_Mode *mode;
|
||||||
|
const char *conn_name;
|
||||||
|
char name[32];
|
||||||
|
int i = 0;
|
||||||
|
drmModeEncoder *enc;
|
||||||
|
drmModeModeInfo crtc_mode;
|
||||||
|
drmModeCrtc *crtc;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
i = _ecore_drm_output_crtc_find(dev, res, conn);
|
||||||
|
if (i < 0)
|
||||||
|
{
|
||||||
|
ERR("Could not find crtc or encoder for connector");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to allocate space for output */
|
||||||
|
if (!(output = calloc(1, sizeof(Ecore_Drm_Output))))
|
||||||
|
{
|
||||||
|
ERR("Could not allocate space for output");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->dev = dev;
|
||||||
|
output->x = x;
|
||||||
|
output->y = y;
|
||||||
|
|
||||||
|
output->subpixel = conn->subpixel;
|
||||||
|
output->make = eina_stringshare_add("unknown");
|
||||||
|
output->model = eina_stringshare_add("unknown");
|
||||||
|
|
||||||
|
if (conn->connector_type < ALEN(conn_types))
|
||||||
|
conn_name = conn_types[conn->connector_type];
|
||||||
|
else
|
||||||
|
conn_name = "UNKNOWN";
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "%s%d", conn_name, conn->connector_type_id);
|
||||||
|
output->name = eina_stringshare_add(name);
|
||||||
|
|
||||||
|
output->crtc_id = res->crtcs[i];
|
||||||
|
dev->crtc_allocator |= (1 << output->crtc_id);
|
||||||
|
output->conn_id = conn->connector_id;
|
||||||
|
output->crtc = drmModeGetCrtc(dev->drm.fd, output->crtc_id);
|
||||||
|
|
||||||
|
memset(&mode, 0, sizeof(mode));
|
||||||
|
if ((enc = drmModeGetEncoder(dev->drm.fd, conn->encoder_id)))
|
||||||
|
{
|
||||||
|
crtc = drmModeGetCrtc(dev->drm.fd, enc->crtc_id);
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
if (!crtc) goto mode_err;
|
||||||
|
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])))
|
||||||
|
{
|
||||||
|
ERR("Failed to add mode to output");
|
||||||
|
goto mode_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EINA_LIST_REVERSE_FOREACH(output->modes, l, mode)
|
||||||
|
{
|
||||||
|
if (!memcmp(&crtc_mode, &mode->info, sizeof(crtc_mode)))
|
||||||
|
{
|
||||||
|
output->current_mode = mode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!output->current_mode)
|
||||||
|
output->current_mode = _ecore_drm_output_mode_add(output, &crtc_mode);
|
||||||
|
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* if ((dev->use_hw_accel) && (dev->gbm)) */
|
||||||
|
/* { */
|
||||||
|
/* if (!_ecore_drm_output_hardware_setup(dev, output)) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not setup output for hardware acceleration"); */
|
||||||
|
/* dev->use_hw_accel = EINA_FALSE; */
|
||||||
|
/* if (!_ecore_drm_output_software_setup(dev, output)) */
|
||||||
|
/* goto mode_err; */
|
||||||
|
/* else */
|
||||||
|
/* DBG("Setup Output %d for Software Rendering", output->crtc_id); */
|
||||||
|
/* } */
|
||||||
|
/* else */
|
||||||
|
/* DBG("Setup Output %d for Hardware Acceleration", output->crtc_id); */
|
||||||
|
/* } */
|
||||||
|
/* else */
|
||||||
|
/* #endif */
|
||||||
|
{
|
||||||
|
dev->use_hw_accel = EINA_FALSE;
|
||||||
|
if (!_ecore_drm_output_software_setup(dev, output))
|
||||||
|
goto mode_err;
|
||||||
|
else
|
||||||
|
DBG("Setup Output %d for Software Rendering", output->crtc_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
|
||||||
|
return output;
|
||||||
|
|
||||||
|
mode_err:
|
||||||
|
EINA_LIST_FREE(output->modes, mode)
|
||||||
|
free(mode);
|
||||||
|
drmModeFreeCrtc(output->crtc);
|
||||||
|
dev->crtc_allocator &= ~(1 << output->crtc_id);
|
||||||
|
free(output);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if ((fb->mmap) && (fb != output->dumb[0]) && (fb != output->dumb[1]))
|
||||||
|
ecore_drm_fb_destroy(fb);
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* else if (fb->bo) */
|
||||||
|
/* gbm_bo_destroy(fb->bo); */
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_ecore_drm_output_repaint_start(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
unsigned int fb;
|
||||||
|
|
||||||
|
DBG("Output Repaint Start");
|
||||||
|
|
||||||
|
if (!output) return;
|
||||||
|
|
||||||
|
if (!output->current)
|
||||||
|
{
|
||||||
|
DBG("\tNo Current FB");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb = output->current->id;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Output_Group
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO: DOXY !! */
|
||||||
|
|
||||||
|
/* public functions */
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_outputs_create(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Eina_Bool ret = EINA_TRUE;
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
drmModeConnector *conn;
|
||||||
|
drmModeRes *res;
|
||||||
|
drmModeCrtc *crtc;
|
||||||
|
int i = 0, x = 0, y = 0;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
for (i = 0; i < res->count_connectors; i++)
|
||||||
|
{
|
||||||
|
if (i > 0) break;
|
||||||
|
/* get the connector */
|
||||||
|
if (!(conn = drmModeGetConnector(dev->drm.fd, res->connectors[i])))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((conn->connection == DRM_MODE_CONNECTED) &&
|
||||||
|
(conn->count_modes > 0))
|
||||||
|
{
|
||||||
|
drmModeEncoder *enc;
|
||||||
|
|
||||||
|
/* create output for this connector */
|
||||||
|
if (!(output = _ecore_drm_output_create(dev, res, conn, x, y)))
|
||||||
|
{
|
||||||
|
/* free the connector */
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->drm_fd = dev->drm.fd;
|
||||||
|
dev->outputs = eina_list_append(dev->outputs, output);
|
||||||
|
|
||||||
|
if (!(enc = drmModeGetEncoder(dev->drm.fd, conn->encoder_id)))
|
||||||
|
{
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(crtc = drmModeGetCrtc(dev->drm.fd, enc->crtc_id)))
|
||||||
|
{
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
x += crtc->width;
|
||||||
|
|
||||||
|
drmModeFreeCrtc(crtc);
|
||||||
|
drmModeFreeEncoder(enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free the connector */
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = EINA_TRUE;
|
||||||
|
if (eina_list_count(dev->outputs) < 1)
|
||||||
|
{
|
||||||
|
ret = EINA_FALSE;
|
||||||
|
free(dev->crtcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free resources */
|
||||||
|
drmModeFreeResources(res);
|
||||||
|
|
||||||
|
/* TODO: add hook for udev drm output updates */
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_output_free(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output_Mode *mode;
|
||||||
|
|
||||||
|
/* check for valid output */
|
||||||
|
if (!output) return;
|
||||||
|
|
||||||
|
/* free modes */
|
||||||
|
EINA_LIST_FREE(output->modes, mode)
|
||||||
|
free(mode);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
free(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_output_cursor_size_set(Ecore_Drm_Output *output, int handle, int w, int h)
|
||||||
|
{
|
||||||
|
if (!output) return;
|
||||||
|
drmModeSetCursor(output->drm_fd, output->crtc_id, handle, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_output_enable(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output_Mode *mode;
|
||||||
|
|
||||||
|
if ((!output) || (!output->current)) return EINA_FALSE;
|
||||||
|
|
||||||
|
mode = output->current_mode;
|
||||||
|
if (drmModeSetCrtc(output->drm_fd, output->crtc_id, output->current->id,
|
||||||
|
0, 0, &output->conn_id, 1, &mode->info) < 0)
|
||||||
|
{
|
||||||
|
ERR("Could not set output crtc: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb)
|
||||||
|
{
|
||||||
|
if ((!output) || (!fb)) return;
|
||||||
|
|
||||||
|
if ((fb->mmap) && (fb != output->dumb[0]) && (fb != output->dumb[1]))
|
||||||
|
ecore_drm_fb_destroy(fb);
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* else if (fb->bo) */
|
||||||
|
/* { */
|
||||||
|
/* if (fb->from_client) */
|
||||||
|
/* gbm_bo_destroy(fb->bo); */
|
||||||
|
/* else */
|
||||||
|
/* gbm_surface_release_buffer(output->surface, fb->bo); */
|
||||||
|
/* } */
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_output_repaint(Ecore_Drm_Output *output)
|
||||||
|
{
|
||||||
|
Eina_List *l;
|
||||||
|
Ecore_Drm_Sprite *sprite;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!output) return;
|
||||||
|
|
||||||
|
DBG("Output Repaint: %d %d", output->crtc_id, output->conn_id);
|
||||||
|
|
||||||
|
/* TODO: assign planes ? */
|
||||||
|
|
||||||
|
if (!output->next)
|
||||||
|
{
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* if (output->dev->use_hw_accel) */
|
||||||
|
/* { */
|
||||||
|
/* _ecore_drm_output_hardware_render(output); */
|
||||||
|
/* } */
|
||||||
|
/* else */
|
||||||
|
/* #endif */
|
||||||
|
{
|
||||||
|
_ecore_drm_output_software_render(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!output->next)
|
||||||
|
{
|
||||||
|
DBG("\tNo Next Fb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->need_repaint = EINA_FALSE;
|
||||||
|
|
||||||
|
if (!output->current)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output_Mode *mode;
|
||||||
|
|
||||||
|
mode = output->current_mode;
|
||||||
|
|
||||||
|
ret = drmModeSetCrtc(output->dev->drm.fd, output->crtc_id,
|
||||||
|
output->next->id, 0, 0, &output->conn_id, 1,
|
||||||
|
&mode->info);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
ERR("Setting output mode failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drmModePageFlip(output->dev->drm.fd, output->crtc_id, output->next->id,
|
||||||
|
DRM_MODE_PAGE_FLIP_EVENT, output) < 0)
|
||||||
|
{
|
||||||
|
ERR("Scheduling pageflip failed");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->pending_flip = EINA_TRUE;
|
||||||
|
|
||||||
|
EINA_LIST_FOREACH(output->dev->sprites, l, sprite)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
if ((sprite->next_fb) && (!output->dev->cursors_broken))
|
||||||
|
id = sprite->next_fb->id;
|
||||||
|
|
||||||
|
ecore_drm_sprites_fb_set(sprite, id, flags);
|
||||||
|
|
||||||
|
vbl.request.signal = (unsigned long)sprite;
|
||||||
|
ret = drmWaitVBlank(output->dev->drm.fd, &vbl);
|
||||||
|
if (ret) ERR("Error Wait VBlank: %m");
|
||||||
|
|
||||||
|
sprite->output = output;
|
||||||
|
output->pending_vblank = EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (output->next)
|
||||||
|
{
|
||||||
|
ecore_drm_output_fb_release(output, output->next);
|
||||||
|
output->next = NULL;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,281 @@
|
||||||
|
#ifndef _ECORE_DRM_PRIVATE_H
|
||||||
|
# define _ECORE_DRM_PRIVATE_H
|
||||||
|
|
||||||
|
# include "Ecore.h"
|
||||||
|
# include "ecore_private.h"
|
||||||
|
# include "Ecore_Input.h"
|
||||||
|
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <string.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
# include <errno.h>
|
||||||
|
# include <sys/mman.h>
|
||||||
|
# include <fcntl.h>
|
||||||
|
|
||||||
|
# include <libudev.h>
|
||||||
|
# include <linux/input.h>
|
||||||
|
//# include <libinput.h>
|
||||||
|
|
||||||
|
# include <xf86drm.h>
|
||||||
|
# include <xf86drmMode.h>
|
||||||
|
# include <drm_fourcc.h>
|
||||||
|
|
||||||
|
/* # ifdef HAVE_GBM */
|
||||||
|
/* # include <gbm.h> */
|
||||||
|
/* # include <EGL/egl.h> */
|
||||||
|
/* # include <EGL/eglext.h> */
|
||||||
|
/* # include <GLES2/gl2.h> */
|
||||||
|
/* # include <GLES2/gl2ext.h> */
|
||||||
|
/* # endif */
|
||||||
|
|
||||||
|
# include <Ecore_Drm.h>
|
||||||
|
|
||||||
|
# ifndef DRM_MAJOR
|
||||||
|
# define DRM_MAJOR 226
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef DRM_CAP_TIMESTAMP_MONOTONIC
|
||||||
|
# define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef ECORE_DRM_DEFAULT_LOG_COLOR
|
||||||
|
# undef ECORE_DRM_DEFAULT_LOG_COLOR
|
||||||
|
# endif
|
||||||
|
# define ECORE_DRM_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
|
||||||
|
|
||||||
|
# define EVDEV_SEAT_POINTER (1 << 0)
|
||||||
|
# define EVDEV_SEAT_KEYBOARD (1 << 1)
|
||||||
|
# define EVDEV_SEAT_TOUCH (1 << 2)
|
||||||
|
|
||||||
|
# ifdef ERR
|
||||||
|
# undef ERR
|
||||||
|
# endif
|
||||||
|
# ifdef DBG
|
||||||
|
# undef DBG
|
||||||
|
# endif
|
||||||
|
# ifdef INF
|
||||||
|
# undef INF
|
||||||
|
# endif
|
||||||
|
# ifdef WRN
|
||||||
|
# undef WRN
|
||||||
|
# endif
|
||||||
|
# ifdef CRIT
|
||||||
|
# undef CRIT
|
||||||
|
# endif
|
||||||
|
|
||||||
|
extern int _ecore_drm_log_dom;
|
||||||
|
|
||||||
|
/* undef this for non-testing builds */
|
||||||
|
# define LOG_TO_FILE
|
||||||
|
|
||||||
|
# ifdef LOG_TO_FILE
|
||||||
|
extern FILE *lg;
|
||||||
|
|
||||||
|
# define ERR(...) \
|
||||||
|
EINA_LOG_DOM_ERR(_ecore_drm_log_dom, __VA_ARGS__); \
|
||||||
|
fflush(lg);
|
||||||
|
|
||||||
|
# define DBG(...) \
|
||||||
|
EINA_LOG_DOM_DBG(_ecore_drm_log_dom, __VA_ARGS__); \
|
||||||
|
fflush(lg);
|
||||||
|
|
||||||
|
# define INF(...) \
|
||||||
|
EINA_LOG_DOM_INFO(_ecore_drm_log_dom, __VA_ARGS__); \
|
||||||
|
fflush(lg);
|
||||||
|
|
||||||
|
# define WRN(...) \
|
||||||
|
EINA_LOG_DOM_WARN(_ecore_drm_log_dom, __VA_ARGS__); \
|
||||||
|
fflush(lg);
|
||||||
|
|
||||||
|
# define CRIT(...) \
|
||||||
|
EINA_LOG_DOM_CRIT(_ecore_drm_log_dom, __VA_ARGS__); \
|
||||||
|
fflush(lg);
|
||||||
|
|
||||||
|
# else
|
||||||
|
# define ERR(...) EINA_LOG_DOM_ERR(_ecore_drm_log_dom, __VA_ARGS__)
|
||||||
|
# define DBG(...) EINA_LOG_DOM_DBG(_ecore_drm_log_dom, __VA_ARGS__)
|
||||||
|
# define INF(...) EINA_LOG_DOM_INFO(_ecore_drm_log_dom, __VA_ARGS__)
|
||||||
|
# define WRN(...) EINA_LOG_DOM_WARN(_ecore_drm_log_dom, __VA_ARGS__)
|
||||||
|
# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_drm_log_dom, __VA_ARGS__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
extern struct udev *udev;
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Output_Mode
|
||||||
|
{
|
||||||
|
unsigned int flags;
|
||||||
|
int width, height;
|
||||||
|
unsigned int refresh;
|
||||||
|
drmModeModeInfo info;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Output
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
unsigned int crtc_id;
|
||||||
|
unsigned int conn_id;
|
||||||
|
drmModeCrtcPtr crtc;
|
||||||
|
|
||||||
|
int x, y;
|
||||||
|
int drm_fd;
|
||||||
|
|
||||||
|
Eina_Bool need_repaint : 1;
|
||||||
|
Eina_Bool repaint_scheduled : 1;
|
||||||
|
|
||||||
|
Eina_Bool pending_flip : 1;
|
||||||
|
Eina_Bool pending_vblank : 1;
|
||||||
|
|
||||||
|
const char *make, *model, *name;
|
||||||
|
unsigned int subpixel;
|
||||||
|
|
||||||
|
Ecore_Drm_Output_Mode *current_mode;
|
||||||
|
Eina_List *modes;
|
||||||
|
|
||||||
|
Ecore_Drm_Fb *current, *next;
|
||||||
|
Ecore_Drm_Fb *dumb[NUM_FRAME_BUFFERS];
|
||||||
|
|
||||||
|
/* # ifdef HAVE_GBM */
|
||||||
|
/* struct gbm_surface *surface; */
|
||||||
|
/* struct gbm_bo *cursor[NUM_FRAME_BUFFERS]; */
|
||||||
|
/* struct */
|
||||||
|
/* { */
|
||||||
|
/* EGLSurface surface; */
|
||||||
|
/* } egl; */
|
||||||
|
/* # endif */
|
||||||
|
|
||||||
|
/* TODO: finish */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Seat
|
||||||
|
{
|
||||||
|
// struct libinput_seat *seat;
|
||||||
|
const char *name;
|
||||||
|
Ecore_Drm_Input *input;
|
||||||
|
Eina_List *devices;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Input
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
const char *seat;
|
||||||
|
struct udev_monitor *monitor;
|
||||||
|
Ecore_Fd_Handler *hdlr;
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
|
||||||
|
Eina_Bool enabled : 1;
|
||||||
|
Eina_Bool suspended : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Evdev
|
||||||
|
{
|
||||||
|
Ecore_Drm_Seat *seat;
|
||||||
|
/* struct libinput *linput; */
|
||||||
|
/* struct libinput_device *dev; */
|
||||||
|
const char *name, *path;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int min_x, min_y;
|
||||||
|
int max_x, max_y;
|
||||||
|
int x, y;
|
||||||
|
} abs;
|
||||||
|
|
||||||
|
Ecore_Drm_Evdev_Event_Type pending_event;
|
||||||
|
Ecore_Drm_Evdev_Capabilities caps;
|
||||||
|
Ecore_Drm_Seat_Capabilities seat_caps;
|
||||||
|
|
||||||
|
void (*event_process)(Ecore_Drm_Evdev *dev, struct input_event *event, int count);
|
||||||
|
|
||||||
|
Ecore_Fd_Handler *hdlr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Sprite
|
||||||
|
{
|
||||||
|
Ecore_Drm_Fb *current_fb, *next_fb;
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
|
||||||
|
int drm_fd;
|
||||||
|
|
||||||
|
unsigned int crtcs;
|
||||||
|
unsigned int plane_id;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
unsigned int w, h;
|
||||||
|
} src, dest;
|
||||||
|
|
||||||
|
unsigned int num_formats;
|
||||||
|
unsigned int formats[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Ecore_Drm_Device
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
const char *seat;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
const char *name;
|
||||||
|
const char *path;
|
||||||
|
clockid_t clock;
|
||||||
|
Ecore_Fd_Handler *hdlr;
|
||||||
|
Ecore_Idle_Enterer *idler;
|
||||||
|
} drm;
|
||||||
|
|
||||||
|
unsigned int min_width, min_height;
|
||||||
|
unsigned int max_width, max_height;
|
||||||
|
|
||||||
|
unsigned int crtc_count;
|
||||||
|
unsigned int *crtcs;
|
||||||
|
unsigned int crtc_allocator;
|
||||||
|
|
||||||
|
Eina_List *seats;
|
||||||
|
Eina_List *inputs;
|
||||||
|
Eina_List *outputs;
|
||||||
|
Eina_List *sprites;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
const char *name;
|
||||||
|
Ecore_Event_Handler *event_hdlr;
|
||||||
|
} tty;
|
||||||
|
|
||||||
|
unsigned int format;
|
||||||
|
Eina_Bool use_hw_accel : 1;
|
||||||
|
Eina_Bool cursors_broken : 1;
|
||||||
|
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* struct gbm_device *gbm; */
|
||||||
|
/* struct */
|
||||||
|
/* { */
|
||||||
|
/* EGLDisplay disp; */
|
||||||
|
/* EGLContext ctxt; */
|
||||||
|
/* EGLConfig cfg; */
|
||||||
|
/* } egl; */
|
||||||
|
/* #endif */
|
||||||
|
};
|
||||||
|
|
||||||
|
void _ecore_drm_message_send(int opcode, int fd, void *data, size_t bytes);
|
||||||
|
Eina_Bool _ecore_drm_message_receive(int opcode, int *fd, void **data, size_t bytes);
|
||||||
|
|
||||||
|
Ecore_Drm_Evdev *_ecore_drm_evdev_device_create(Ecore_Drm_Seat *seat, const char *path, int fd);
|
||||||
|
void _ecore_drm_evdev_device_destroy(Ecore_Drm_Evdev *evdev);
|
||||||
|
/* int _ecore_drm_evdev_event_process(struct libinput_event *event); */
|
||||||
|
|
||||||
|
Ecore_Drm_Fb *_ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height);
|
||||||
|
void _ecore_drm_fb_destroy(Ecore_Drm_Fb *fb);
|
||||||
|
|
||||||
|
/* #ifdef HAVE_GBM */
|
||||||
|
/* Ecore_Drm_Fb *_ecore_drm_fb_bo_get(Ecore_Drm_Device *dev, struct gbm_bo *bo); */
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
void _ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb);
|
||||||
|
void _ecore_drm_output_repaint_start(Ecore_Drm_Output *output);
|
||||||
|
void _ecore_drm_output_frame_finish(Ecore_Drm_Output *output);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,115 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Fb_Group
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO: DOXY !! */
|
||||||
|
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_sprites_create(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
drmModePlaneRes *res;
|
||||||
|
drmModePlane *p;
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* get plane resources */
|
||||||
|
if (!(res = drmModeGetPlaneResources(dev->drm.fd))) return EINA_FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < res->count_planes; i++)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Sprite *sprite;
|
||||||
|
|
||||||
|
if (!(p = drmModeGetPlane(dev->drm.fd, res->planes[i])))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* allocate space for sprite */
|
||||||
|
if (!(sprite =
|
||||||
|
malloc(sizeof(Ecore_Drm_Sprite) +
|
||||||
|
((sizeof(unsigned int)) * p->count_formats))))
|
||||||
|
{
|
||||||
|
drmModeFreePlane(p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprite->drm_fd = dev->drm.fd;
|
||||||
|
sprite->crtcs = p->possible_crtcs;
|
||||||
|
sprite->plane_id = p->plane_id;
|
||||||
|
sprite->num_formats = p->count_formats;
|
||||||
|
memcpy(sprite->formats, p->formats,
|
||||||
|
p->count_formats * sizeof(p->formats[0]));
|
||||||
|
drmModeFreePlane(p);
|
||||||
|
|
||||||
|
dev->sprites = eina_list_append(dev->sprites, sprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free resources */
|
||||||
|
drmModeFreePlaneResources(res);
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_sprites_destroy(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Sprite *sprite;
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if (!dev) return;
|
||||||
|
|
||||||
|
EINA_LIST_FREE(dev->sprites, sprite)
|
||||||
|
{
|
||||||
|
ecore_drm_sprites_fb_set(sprite, 0, 0);
|
||||||
|
|
||||||
|
_ecore_drm_output_fb_release(sprite->output, sprite->current_fb);
|
||||||
|
_ecore_drm_output_fb_release(sprite->output, sprite->next_fb);
|
||||||
|
|
||||||
|
free(sprite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ecore_drm_sprites_fb_set(Ecore_Drm_Sprite *sprite, int fb_id, int flags)
|
||||||
|
{
|
||||||
|
if ((!sprite) || (!sprite->output)) return;
|
||||||
|
|
||||||
|
if (fb_id)
|
||||||
|
{
|
||||||
|
drmModeSetPlane(sprite->drm_fd, sprite->plane_id,
|
||||||
|
sprite->output->crtc_id, fb_id, flags,
|
||||||
|
sprite->dest.x, sprite->dest.y, sprite->dest.w,
|
||||||
|
sprite->dest.h, sprite->src.x, sprite->src.y,
|
||||||
|
sprite->src.w, sprite->src.h);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drmModeSetPlane(sprite->drm_fd, sprite->plane_id,
|
||||||
|
sprite->output->crtc_id, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_sprites_crtc_supported(Ecore_Drm_Output *output, unsigned int supported)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
unsigned int c = 0;
|
||||||
|
|
||||||
|
dev = output->dev;
|
||||||
|
|
||||||
|
for (c = 0; c < dev->crtc_count; c++)
|
||||||
|
{
|
||||||
|
if (dev->crtcs[c] != output->crtc_id) continue;
|
||||||
|
if ((supported) && (1 << c)) return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
|
@ -0,0 +1,297 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ecore_drm_private.h"
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/vt.h>
|
||||||
|
#include <linux/kd.h>
|
||||||
|
|
||||||
|
#ifndef KDSKBMUTE
|
||||||
|
# define KDSKBMUTE 0x4B51
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_tty_cb_signal(void *data, int type EINA_UNUSED, void *event)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Device *dev;
|
||||||
|
Ecore_Event_Signal_User *ev;
|
||||||
|
|
||||||
|
dev = data;
|
||||||
|
ev = event;
|
||||||
|
|
||||||
|
DBG("Caught user signal: %d", ev->number);
|
||||||
|
|
||||||
|
if (ev->number == 1)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Input *input;
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
Ecore_Drm_Sprite *sprite;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
DBG("Release VT");
|
||||||
|
|
||||||
|
/* disable inputs (suspends) */
|
||||||
|
EINA_LIST_FOREACH(dev->inputs, l, input)
|
||||||
|
ecore_drm_inputs_disable(input);
|
||||||
|
|
||||||
|
/* disable hardware cursor */
|
||||||
|
EINA_LIST_FOREACH(dev->outputs, l, output)
|
||||||
|
ecore_drm_output_cursor_size_set(output, 0, 0, 0);
|
||||||
|
|
||||||
|
/* disable sprites */
|
||||||
|
EINA_LIST_FOREACH(dev->sprites, l, sprite)
|
||||||
|
ecore_drm_sprites_fb_set(sprite, 0, 0);
|
||||||
|
|
||||||
|
/* close input fds ?? */
|
||||||
|
|
||||||
|
/* drop drm master */
|
||||||
|
if (ecore_drm_device_master_drop(dev))
|
||||||
|
{
|
||||||
|
/* issue ioctl to release vt */
|
||||||
|
if (!ecore_drm_tty_release(dev))
|
||||||
|
ERR("Could not release VT: %m");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ERR("Could not drop drm master: %m");
|
||||||
|
}
|
||||||
|
else if (ev->number == 2)
|
||||||
|
{
|
||||||
|
Ecore_Drm_Output *output;
|
||||||
|
Ecore_Drm_Input *input;
|
||||||
|
Eina_List *l;
|
||||||
|
|
||||||
|
DBG("Acquire VT");
|
||||||
|
|
||||||
|
/* issue ioctl to acquire vt */
|
||||||
|
if (ecore_drm_tty_acquire(dev))
|
||||||
|
{
|
||||||
|
/* set drm master */
|
||||||
|
if (!ecore_drm_device_master_set(dev))
|
||||||
|
ERR("Could not set drm master: %m");
|
||||||
|
|
||||||
|
/* set output mode */
|
||||||
|
EINA_LIST_FOREACH(dev->outputs, l, output)
|
||||||
|
ecore_drm_output_enable(output);
|
||||||
|
|
||||||
|
/* enable inputs */
|
||||||
|
EINA_LIST_FOREACH(dev->inputs, l, input)
|
||||||
|
ecore_drm_inputs_enable(input);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ERR("Could not acquire VT: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_ecore_drm_tty_setup(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int kb_mode;
|
||||||
|
struct vt_mode vtmode = { 0 };
|
||||||
|
|
||||||
|
if (fstat(dev->tty.fd, &st) == -1)
|
||||||
|
{
|
||||||
|
ERR("Failed to get stats for tty: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(dev->tty.fd, KDGKBMODE, &kb_mode))
|
||||||
|
{
|
||||||
|
ERR("Could not get tty keyboard mode: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NB: Don't set this. This Turns OFF keyboard on the VT */
|
||||||
|
/* if (ioctl(dev->tty.fd, KDSKBMUTE, 1) && */
|
||||||
|
/* ioctl(dev->tty.fd, KDSKBMODE, K_OFF)) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not set K_OFF keyboard mode: %m"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (ioctl(dev->tty.fd, KDSETMODE, KD_GRAPHICS)) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Could not set graphics mode: %m"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
vtmode.mode = VT_PROCESS;
|
||||||
|
vtmode.waitv = 0;
|
||||||
|
vtmode.relsig = SIGUSR1;
|
||||||
|
vtmode.acqsig = SIGUSR2;
|
||||||
|
if (ioctl(dev->tty.fd, VT_SETMODE, &vtmode) < 0)
|
||||||
|
{
|
||||||
|
ERR("Could not set Terminal Mode: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if (ioctl(dev->tty.fd, VT_ACTIVATE, minor(st.st_rdev)) < 0) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Failed to activate vt: %m"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (ioctl(dev->tty.fd, VT_WAITACTIVE, minor(st.st_rdev)) < 0) */
|
||||||
|
/* { */
|
||||||
|
/* ERR("Failed to wait active: %m"); */
|
||||||
|
/* return EINA_FALSE; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup Ecore_Drm_Tty_Group Tty manipulation functions
|
||||||
|
*
|
||||||
|
* Functions that deal with opening, closing, and otherwise using a tty
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a tty for use
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device that this tty will belong to.
|
||||||
|
* @param name The name of the tty to try and open.
|
||||||
|
* If NULL, /dev/tty0 will be used.
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Tty_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_tty_open(Ecore_Drm_Device *dev, const char *name)
|
||||||
|
{
|
||||||
|
char tty[32] = "<stdin>";
|
||||||
|
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!dev->drm.name)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* assign default tty fd of -1 */
|
||||||
|
dev->tty.fd = -1;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
char *env;
|
||||||
|
|
||||||
|
if ((env = getenv("ECORE_DRM_TTY")))
|
||||||
|
snprintf(tty, sizeof(tty), "%s", env);
|
||||||
|
else
|
||||||
|
dev->tty.fd = STDIN_FILENO;
|
||||||
|
}
|
||||||
|
else // FIXME: NB: This should Really check for format of name (/dev/xyz)
|
||||||
|
snprintf(tty, sizeof(tty), "%s", name);
|
||||||
|
|
||||||
|
if (dev->tty.fd < 0)
|
||||||
|
{
|
||||||
|
DBG("Trying to Open Tty: %s", tty);
|
||||||
|
|
||||||
|
dev->tty.fd = open(tty, O_RDWR | O_NOCTTY);
|
||||||
|
if (dev->tty.fd < 0)
|
||||||
|
{
|
||||||
|
DBG("Failed to Open Tty: %m");
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->tty.fd < 0)
|
||||||
|
{
|
||||||
|
DBG("Failed to open tty %s", tty);
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG("Opened Tty %s : %d", tty, dev->tty.fd);
|
||||||
|
|
||||||
|
/* save tty name */
|
||||||
|
dev->tty.name = eina_stringshare_add(tty);
|
||||||
|
|
||||||
|
/* FIXME */
|
||||||
|
if (!_ecore_drm_tty_setup(dev))
|
||||||
|
return EINA_FALSE;
|
||||||
|
|
||||||
|
/* setup handler for signals */
|
||||||
|
dev->tty.event_hdlr =
|
||||||
|
ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER,
|
||||||
|
_ecore_drm_tty_cb_signal, dev);
|
||||||
|
|
||||||
|
/* set current tty into env */
|
||||||
|
setenv("ECORE_DRM_TTY", tty, 1);
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close an already opened tty
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device which owns this tty.
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Tty_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_tty_close(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!dev->drm.name)) return EINA_FALSE;
|
||||||
|
|
||||||
|
close(dev->tty.fd);
|
||||||
|
|
||||||
|
dev->tty.fd = -1;
|
||||||
|
|
||||||
|
/* destroy the event handler */
|
||||||
|
if (dev->tty.event_hdlr) ecore_event_handler_del(dev->tty.event_hdlr);
|
||||||
|
dev->tty.event_hdlr = NULL;
|
||||||
|
|
||||||
|
/* clear the tty name */
|
||||||
|
if (dev->tty.name) eina_stringshare_del(dev->tty.name);
|
||||||
|
dev->tty.name = NULL;
|
||||||
|
|
||||||
|
unsetenv("ECORE_DRM_TTY");
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release a virtual terminal
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device which owns this tty.
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Tty_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_tty_release(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!dev->drm.name) || (dev->tty.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* send ioctl for vt release */
|
||||||
|
if (ioctl(dev->tty.fd, VT_RELDISP, 1) < 0) return EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire a virtual terminal
|
||||||
|
*
|
||||||
|
* @param dev The Ecore_Drm_Device which owns this tty.
|
||||||
|
*
|
||||||
|
* @return EINA_TRUE on success, EINA_FALSE on failure
|
||||||
|
*
|
||||||
|
* @ingroup Ecore_Drm_Tty_Group
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_drm_tty_acquire(Ecore_Drm_Device *dev)
|
||||||
|
{
|
||||||
|
/* check for valid device */
|
||||||
|
if ((!dev) || (!dev->drm.name) || (dev->tty.fd < 0)) return EINA_FALSE;
|
||||||
|
|
||||||
|
/* send ioctl for vt acquire */
|
||||||
|
if (ioctl(dev->tty.fd, VT_RELDISP, VT_ACKACQ) < 0) return EINA_FALSE;
|
||||||
|
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
Loading…
Reference in New Issue