summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Michael <cp.michael@samsung.com>2014-03-06 09:43:48 +0000
committerChris Michael <cp.michael@samsung.com>2014-03-06 10:57:26 +0000
commit3762e85c3967a7a7574c83bf6d550d58e58d90fc (patch)
tree48e695cf560924cf0b800f682371dfe1eb74de7e
parent0f1883df9a978d686971bba9f1450b7eb7a3fd84 (diff)
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>
-rw-r--r--src/lib/ecore_drm/Ecore_Drm.h171
-rw-r--r--src/lib/ecore_drm/ecore_drm.c414
-rw-r--r--src/lib/ecore_drm/ecore_drm_device.c583
-rw-r--r--src/lib/ecore_drm/ecore_drm_evdev.c360
-rw-r--r--src/lib/ecore_drm/ecore_drm_fb.c151
-rw-r--r--src/lib/ecore_drm/ecore_drm_inputs.c303
-rw-r--r--src/lib/ecore_drm/ecore_drm_output.c703
-rw-r--r--src/lib/ecore_drm/ecore_drm_private.h281
-rw-r--r--src/lib/ecore_drm/ecore_drm_sprites.c115
-rw-r--r--src/lib/ecore_drm/ecore_drm_tty.c297
10 files changed, 3378 insertions, 0 deletions
diff --git a/src/lib/ecore_drm/Ecore_Drm.h b/src/lib/ecore_drm/Ecore_Drm.h
new file mode 100644
index 0000000000..e89d2df5b0
--- /dev/null
+++ b/src/lib/ecore_drm/Ecore_Drm.h
@@ -0,0 +1,171 @@
1#ifndef _ECORE_DRM_H
2# define _ECORE_DRM_H
3
4# ifdef EAPI
5# undef EAPI
6# endif
7
8#ifdef _MSC_VER
9# ifdef BUILDING_DLL
10# define EAPI __declspec(dllexport)
11# else // ifdef BUILDING_DLL
12# define EAPI __declspec(dllimport)
13# endif // ifdef BUILDING_DLL
14#else // ifdef _MSC_VER
15# ifdef __GNUC__
16# if __GNUC__ >= 4
17# define EAPI __attribute__ ((visibility("default")))
18# else // if __GNUC__ >= 4
19# define EAPI
20# endif // if __GNUC__ >= 4
21# else // ifdef __GNUC__
22# define EAPI
23# endif // ifdef __GNUC__
24#endif // ifdef _MSC_VER
25
26typedef enum _Ecore_Drm_Op
27{
28 ECORE_DRM_OP_READ_FD_SET,
29 ECORE_DRM_OP_WRITE_FD_SET,
30 ECORE_DRM_OP_DEVICE_OPEN,
31 ECORE_DRM_OP_DEVICE_CLOSE,
32 ECORE_DRM_OP_DEVICE_MASTER_DROP,
33 ECORE_DRM_OP_DEVICE_MASTER_SET,
34 ECORE_DRM_OP_TTY_OPEN,
35 ECORE_DRM_OP_TTY_CLOSE
36} Ecore_Drm_Op;
37
38typedef enum _Ecore_Drm_Op_Result
39{
40 ECORE_DRM_OP_SUCCESS,
41 ECORE_DRM_OP_FAILURE
42} Ecore_Drm_Op_Result;
43
44typedef enum _Ecore_Drm_Evdev_Capabilities
45{
46 EVDEV_KEYBOARD = (1 << 0),
47 EVDEV_BUTTON = (1 << 1),
48 EVDEV_MOTION_ABS = (1 << 2),
49 EVDEV_MOTION_REL = (1 << 3),
50 EVDEV_TOUCH = (1 << 4),
51} Ecore_Drm_Evdev_Capabilities;
52
53typedef enum _Ecore_Drm_Evdev_Event_Type
54{
55 EVDEV_NONE,
56 EVDEV_ABSOLUTE_TOUCH_DOWN,
57 EVDEV_ABSOLUTE_MOTION,
58 EVDEV_ABSOLUTE_TOUCH_UP,
59 EVDEV_ABSOLUTE_MT_DOWN,
60 EVDEV_ABSOLUTE_MT_MOTION,
61 EVDEV_ABSOLUTE_MT_UP,
62 EVDEV_RELATIVE_MOTION,
63} Ecore_Drm_Evdev_Event_Type;
64
65typedef enum _Ecore_Drm_Seat_Capabilities
66{
67 EVDEV_SEAT_POINTER = (1 << 0),
68 EVDEV_SEAT_KEYBOARD = (1 << 1),
69 EVDEV_SEAT_TOUCH = (1 << 2),
70} Ecore_Drm_Seat_Capabilities;
71
72/* structure for message passing */
73typedef struct _Ecore_Drm_Message
74{
75 int opcode, size;
76 void *data;
77} Ecore_Drm_Message;
78
79/* structure for fb objects */
80typedef struct _Ecore_Drm_Fb
81{
82 Eina_Bool from_client : 1;
83 unsigned int id, hdl;
84 unsigned int stride, size;
85 int fd;
86 void *mmap;
87/* #ifdef HAVE_GBM */
88/* struct gbm_bo *bo; */
89/* #endif */
90} Ecore_Drm_Fb;
91
92/* opaque structure to represent a drm device */
93typedef struct _Ecore_Drm_Device Ecore_Drm_Device;
94
95/* opaque structure to represent a drm output mode */
96typedef struct _Ecore_Drm_Output_Mode Ecore_Drm_Output_Mode;
97
98/* opaque structure to represent a drm output */
99typedef struct _Ecore_Drm_Output Ecore_Drm_Output;
100
101/* opaque structure to represent a drm udev input */
102typedef struct _Ecore_Drm_Input Ecore_Drm_Input;
103
104/* opaque structure to represent a drm evdev input */
105typedef struct _Ecore_Drm_Evdev Ecore_Drm_Evdev;
106
107/* opaque structure to represent a drm seat */
108typedef struct _Ecore_Drm_Seat Ecore_Drm_Seat;
109
110/* opaque structure to represent a drm sprite */
111typedef struct _Ecore_Drm_Sprite Ecore_Drm_Sprite;
112
113/**
114 * @file
115 * @brief Ecore functions for dealing with drm, virtual terminals
116 *
117 * @defgroup Ecore_Drm_Group Ecore_Drm - Drm Integration
118 * @ingroup Ecore
119 *
120 * Ecore_Drm provides a wrapper and functions for using libdrm
121 *
122 * @li @ref Ecore_Drm_Init_Group
123 * @li @ref Ecore_Drm_Device_Group
124 * @li @ref Ecore_Drm_Tty_Group
125 * @li @ref Ecore_Drm_Output_Group
126 * @li @ref Ecore_Drm_Input_Group
127 * @li @ref Ecore_Drm_Sprite_Group
128 *
129 */
130
131EAPI int ecore_drm_init(void);
132EAPI int ecore_drm_shutdown(void);
133
134/* EAPI void *ecore_drm_gbm_get(Ecore_Drm_Device *dev); */
135/* EAPI unsigned int ecore_drm_gbm_format_get(Ecore_Drm_Device *dev); */
136
137EAPI Ecore_Drm_Device *ecore_drm_device_find(const char *name, const char *seat);
138EAPI void ecore_drm_device_free(Ecore_Drm_Device *dev);
139EAPI Eina_Bool ecore_drm_device_open(Ecore_Drm_Device *dev);
140EAPI Eina_Bool ecore_drm_device_close(Ecore_Drm_Device *dev);
141EAPI Eina_Bool ecore_drm_device_master_get(Ecore_Drm_Device *dev);
142EAPI Eina_Bool ecore_drm_device_master_set(Ecore_Drm_Device *dev);
143EAPI Eina_Bool ecore_drm_device_master_drop(Ecore_Drm_Device *dev);
144EAPI int ecore_drm_device_fd_get(Ecore_Drm_Device *dev);
145
146EAPI Eina_Bool ecore_drm_tty_open(Ecore_Drm_Device *dev, const char *name);
147EAPI Eina_Bool ecore_drm_tty_close(Ecore_Drm_Device *dev);
148EAPI Eina_Bool ecore_drm_tty_release(Ecore_Drm_Device *dev);
149EAPI Eina_Bool ecore_drm_tty_acquire(Ecore_Drm_Device *dev);
150
151EAPI Eina_Bool ecore_drm_outputs_create(Ecore_Drm_Device *dev);
152EAPI void ecore_drm_output_free(Ecore_Drm_Output *output);
153EAPI void ecore_drm_output_cursor_size_set(Ecore_Drm_Output *output, int handle, int w, int h);
154EAPI Eina_Bool ecore_drm_output_enable(Ecore_Drm_Output *output);
155EAPI void ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb);
156EAPI void ecore_drm_output_repaint(Ecore_Drm_Output *output);
157
158EAPI Eina_Bool ecore_drm_inputs_create(Ecore_Drm_Device *dev);
159EAPI void ecore_drm_inputs_destroy(Ecore_Drm_Device *dev);
160EAPI Eina_Bool ecore_drm_inputs_enable(Ecore_Drm_Input *input);
161EAPI void ecore_drm_inputs_disable(Ecore_Drm_Input *input);
162
163EAPI Eina_Bool ecore_drm_sprites_create(Ecore_Drm_Device *dev);
164EAPI void ecore_drm_sprites_destroy(Ecore_Drm_Device *dev);
165EAPI void ecore_drm_sprites_fb_set(Ecore_Drm_Sprite *sprite, int fb_id, int flags);
166EAPI Eina_Bool ecore_drm_sprites_crtc_supported(Ecore_Drm_Output *output, unsigned int supported);
167
168EAPI Ecore_Drm_Fb *ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height);
169EAPI void ecore_drm_fb_destroy(Ecore_Drm_Fb *fb);
170
171#endif
diff --git a/src/lib/ecore_drm/ecore_drm.c b/src/lib/ecore_drm/ecore_drm.c
new file mode 100644
index 0000000000..ac181e379e
--- /dev/null
+++ b/src/lib/ecore_drm/ecore_drm.c
@@ -0,0 +1,414 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include "ecore_drm_private.h"
6#include <sys/wait.h>
7#include <sys/socket.h>
8#include <signal.h>
9
10#define RIGHTS_LEN CMSG_LEN(sizeof(int))
11
12#define IOVSET(_iov, _addr, _len) \
13 (_iov)->iov_base = (void *)(_addr); \
14 (_iov)->iov_len = (_len);
15
16/* local variables */
17static int _ecore_drm_init_count = 0;
18static int _ecore_drm_sockets[2] = { -1, -1 };
19static struct cmsghdr *cmsgptr = NULL;
20
21/* external variables */
22struct udev *udev;
23int _ecore_drm_log_dom = -1;
24#ifdef LOG_TO_FILE
25FILE *lg;
26#endif
27
28static Eina_Bool
29_ecore_drm_sockets_create(void)
30{
31 if (_ecore_drm_sockets[0] > -1) return EINA_TRUE;
32
33 /* create a pair of sequenced sockets (fixed-length)
34 * NB: when reading from one of these, it is required that we read
35 * an entire packet with each read() call */
36 if (socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_NONBLOCK,
37 0, _ecore_drm_sockets) < 0)
38 {
39 ERR("Socketpair Failed: %m");
40 return EINA_FALSE;
41 }
42
43 /* NB: We don't want cloexec for the sockets. That would cause them to be
44 * closed when we exec the child process but we need them open so that
45 * we can pass messages */
46 /* if (fcntl(_ecore_drm_sockets[0], F_SETFD, FD_CLOEXEC) < 0) */
47 /* { */
48 /* ERR("Failed to set CLOEXEC: %m"); */
49 /* return EINA_FALSE; */
50 /* } */
51
52 /* DBG("Parent Socket: %d", _ecore_drm_sockets[0]); */
53 /* DBG("Child Socket: %d", _ecore_drm_sockets[1]); */
54
55 return EINA_TRUE;
56}
57
58static Eina_Bool
59_ecore_drm_launcher_spawn(void)
60{
61 pid_t pid;
62
63 if ((pid = fork()) < 0) return EINA_FALSE;
64
65 if (pid == 0)
66 {
67 char renv[64], wenv[64], buff[PATH_MAX];
68 char *args[1] = { NULL };
69 sigset_t mask;
70
71 /* read socket for slave is 1 */
72 snprintf(renv, sizeof(renv), "ECORE_DRM_LAUNCHER_SOCKET_READ=%d",
73 _ecore_drm_sockets[1]);
74
75 /* write socket for slave is 0 */
76 snprintf(wenv, sizeof(wenv), "ECORE_DRM_LAUNCHER_SOCKET_WRITE=%d",
77 _ecore_drm_sockets[0]);
78
79 /* assemble exec path */
80 snprintf(buff, sizeof(buff),
81 "%s/ecore_drm/bin/%s/ecore_drm_launch",
82 PACKAGE_LIB_DIR, MODULE_ARCH);
83
84 /* don't give our signal mask to the child */
85 sigemptyset(&mask);
86 sigaddset(&mask, SIGTERM);
87 sigaddset(&mask, SIGCHLD);
88 sigaddset(&mask, SIGINT);
89 sigaddset(&mask, SIGTTIN);
90 sigaddset(&mask, SIGTTOU);
91 sigprocmask(SIG_UNBLOCK, &mask, NULL);
92
93 /* NB: We need to use execve here so that capabilities are inherited.
94 * Also, this should set Our (ecore_drm) effective uid to be the
95 * owner of the launched process (setuid in this case) */
96 char *ev[3] = { strdup(renv), strdup(wenv), NULL };
97 execve(buff, args, ev);
98 }
99 else
100 {
101 int status;
102
103 while (waitpid(pid, &status, WNOHANG) < 0)
104 if (errno != EINTR) break;
105
106 return EINA_TRUE;
107 }
108
109 return EINA_FALSE;
110}
111
112static ssize_t
113_ecore_drm_socket_send(int opcode, int fd, void *data, size_t bytes)
114{
115 Ecore_Drm_Message dmsg;
116 struct iovec iov[2];
117 struct msghdr msg;
118 ssize_t size;
119
120 /* Simplified version of sending messages. We don't need to send any
121 * 'credentials' with this as it is just basically an IPC to send over
122 * our request to the slave process */
123
124 /* NB: Hmm, don't think we need to set any socket options here */
125
126 memset(&dmsg, 0, sizeof(dmsg));
127
128 IOVSET(iov + 0, &dmsg, sizeof(dmsg));
129 IOVSET(iov + 1, &data, bytes);
130
131 dmsg.opcode = opcode;
132 dmsg.size = bytes;
133
134 msg.msg_name = NULL;
135 msg.msg_namelen = 0;
136 msg.msg_iov = iov;
137 msg.msg_iovlen = 2;
138 msg.msg_flags = 0;
139
140 if ((!cmsgptr) && (!(cmsgptr = malloc(RIGHTS_LEN))))
141 return -1;
142
143 cmsgptr->cmsg_level = SOL_SOCKET;
144 cmsgptr->cmsg_type = SCM_RIGHTS;
145 cmsgptr->cmsg_len = RIGHTS_LEN;
146
147 msg.msg_control = cmsgptr;
148 msg.msg_controllen = RIGHTS_LEN;
149
150 if (fd > -1)
151 *((int *)CMSG_DATA(cmsgptr)) = fd;
152 else
153 *((int *)CMSG_DATA(cmsgptr)) = _ecore_drm_sockets[1];
154
155 errno = 0;
156 size = sendmsg(_ecore_drm_sockets[1], &msg, MSG_EOR);
157 if (errno != 0)
158 {
159 DBG("Error Sending Message: %m");
160 }
161
162 /* DBG("Sent %li bytes to Socket %d", size, _ecore_drm_sockets[1]); */
163
164 return size;
165}
166
167static int
168_ecore_drm_socket_receive(int opcode EINA_UNUSED, int *fd, void **data, size_t bytes)
169{
170 int ret = ECORE_DRM_OP_FAILURE;
171 Ecore_Drm_Message dmsg;
172 struct cmsghdr *cmsg;
173 struct iovec iov[2];
174 struct msghdr msg;
175 char buff[CMSG_SPACE(sizeof(fd))];
176 /* ssize_t size; */
177
178 memset(&dmsg, 0, sizeof(dmsg));
179 memset(&buff, 0, sizeof(buff));
180
181 IOVSET(iov + 0, &dmsg, sizeof(dmsg));
182 IOVSET(iov + 1, &buff, sizeof(buff));
183
184 msg.msg_name = NULL;
185 msg.msg_namelen = 0;
186 msg.msg_iov = iov;
187 msg.msg_iovlen = 2;
188 msg.msg_flags = 0;
189
190 if ((!cmsgptr) && (!(cmsgptr = malloc(RIGHTS_LEN))))
191 return -1;
192
193 msg.msg_control = cmsgptr;
194 msg.msg_controllen = RIGHTS_LEN;
195
196 errno = 0;
197 recvmsg(_ecore_drm_sockets[0], &msg, 0);
198 if (errno != 0)
199 {
200 ERR("Failed to receive message: %m");
201 return -1;
202 }
203
204 /* DBG("Received %li bytes from %d", size, _ecore_drm_sockets[0]); */
205
206 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
207 cmsg = CMSG_NXTHDR(&msg, cmsg))
208 {
209 if (cmsg->cmsg_level != SOL_SOCKET)
210 continue;
211
212 switch (cmsg->cmsg_type)
213 {
214 case SCM_RIGHTS:
215 if (fd) *fd = *((int *)CMSG_DATA(cmsg));
216 switch (dmsg.opcode)
217 {
218 case ECORE_DRM_OP_DEVICE_OPEN:
219 case ECORE_DRM_OP_DEVICE_CLOSE:
220 case ECORE_DRM_OP_TTY_OPEN:
221 case ECORE_DRM_OP_DEVICE_MASTER_DROP:
222 case ECORE_DRM_OP_DEVICE_MASTER_SET:
223 if ((fd) && (*fd >= 0)) ret = ECORE_DRM_OP_SUCCESS;
224 if (data) memcpy(*data, buff, bytes);
225 break;
226 default:
227 break;
228 }
229 break;
230 default:
231 break;
232 }
233 }
234
235 return ret;
236}
237
238void
239_ecore_drm_message_send(int opcode, int fd, void *data, size_t bytes)
240{
241 _ecore_drm_socket_send(opcode, fd, data, bytes);
242}
243
244Eina_Bool
245_ecore_drm_message_receive(int opcode, int *fd, void **data, size_t bytes)
246{
247 int ret = ECORE_DRM_OP_FAILURE;
248
249 ret = _ecore_drm_socket_receive(opcode, fd, data, bytes);
250 if (ret != ECORE_DRM_OP_SUCCESS) return EINA_FALSE;
251
252 return EINA_TRUE;
253}
254
255/**
256 * @defgroup Ecore_Drm_Init_Group Drm Library Init and Shutdown Functions
257 *
258 * Functions that start and shutdown the Ecore_Drm Library.
259 */
260
261/**
262 * Initialize the Ecore_Drm library
263 *
264 * @return The number of times the library has been initialized without
265 * being shut down. 0 is returned if an error occurs.
266 *
267 * @ingroup Ecore_Drm_Init_Group
268 */
269EAPI int
270ecore_drm_init(void)
271{
272 /* if we have already initialized, return the count */
273 if (++_ecore_drm_init_count != 1) return _ecore_drm_init_count;
274
275 /* try to init eina */
276 if (!eina_init()) return --_ecore_drm_init_count;
277
278 if (!ecore_init())
279 {
280 eina_shutdown();
281 return --_ecore_drm_init_count;
282 }
283
284 /* set logging level */
285 eina_log_level_set(EINA_LOG_LEVEL_DBG);
286
287 setvbuf(stdout, NULL, _IONBF, 0);
288 setvbuf(stderr, NULL, _IONBF, 0);
289
290 /* optionally log output to a file */
291#ifdef LOG_TO_FILE
292 int log_fd;
293 char log_path[PATH_MAX];
294 mode_t um;
295
296 /* assemble logging file path */
297 strcpy(log_path, "/tmp/ecore_drm_XXXXXX");
298
299 /* create temporary logging file */
300 um = umask(S_IRWXG | S_IRWXO);
301 log_fd = mkstemp(log_path);
302 umask(um);
303
304 /* try to open logging file */
305 if (!(lg = fdopen(log_fd, "w")))
306 goto log_err;
307
308 eina_log_print_cb_set(eina_log_print_cb_file, lg);
309#endif
310
311 /* try to create logging domain */
312 _ecore_drm_log_dom =
313 eina_log_domain_register("ecore_drm", ECORE_DRM_DEFAULT_LOG_COLOR);
314 if (!_ecore_drm_log_dom)
315 {
316 EINA_LOG_ERR("Could not create log domain for Ecore_Drm");
317 goto log_err;
318 }
319
320 /* set default logging level for this domain */
321 if (!eina_log_domain_level_check(_ecore_drm_log_dom, EINA_LOG_LEVEL_DBG))
322 eina_log_domain_level_set("ecore_drm", EINA_LOG_LEVEL_DBG);
323
324 /* try to init udev */
325 if (!(udev = udev_new()))
326 goto udev_err;
327
328 /* try to create the socketpair */
329 if (!_ecore_drm_sockets_create())
330 goto sock_err;
331
332 /* try to run Spartacus */
333 if (!_ecore_drm_launcher_spawn())
334 goto spawn_err;
335
336 /* return init count */
337 return _ecore_drm_init_count;
338
339spawn_err:
340 close(_ecore_drm_sockets[0]);
341 close(_ecore_drm_sockets[1]);
342sock_err:
343 if (udev) udev_unref(udev);
344udev_err:
345 ecore_shutdown();
346 eina_log_domain_unregister(_ecore_drm_log_dom);
347 _ecore_drm_log_dom = -1;
348log_err:
349#ifdef LOG_TO_FILE
350 if (lg) fclose(lg);
351#endif
352
353 /* shutdown eina */
354 eina_shutdown();
355
356 return --_ecore_drm_init_count;
357}
358
359/**
360 * Shutdown the Ecore_Drm library.
361 *
362 * @return The number of times the library has been initialized without
363 * being shutdown. 0 is returned if an error occurs.
364 *
365 * @ingroup Ecore_Drm_Init_Group
366 */
367EAPI int
368ecore_drm_shutdown(void)
369{
370 /* if we are still in use, decrement init count and get out */
371 if (--_ecore_drm_init_count != 0) return _ecore_drm_init_count;
372
373 /* close udev handle */
374 if (udev) udev_unref(udev);
375
376 /* close sockets */
377 close(_ecore_drm_sockets[0]);
378 close(_ecore_drm_sockets[1]);
379
380 ecore_shutdown();
381
382 /* unregsiter log domain */
383 eina_log_domain_unregister(_ecore_drm_log_dom);
384 _ecore_drm_log_dom = -1;
385
386#ifdef LOG_TO_FILE
387 if (lg) fclose(lg);
388#endif
389
390 /* shutdown eina */
391 eina_shutdown();
392
393 /* return init count */
394 return _ecore_drm_init_count;
395}
396
397EAPI void *
398ecore_drm_gbm_get(Ecore_Drm_Device *dev)
399{
400 if (!dev) return NULL;
401
402#ifdef HAVE_GBM
403 return dev->gbm;
404#endif
405
406 return NULL;
407}
408
409EAPI unsigned int
410ecore_drm_gbm_format_get(Ecore_Drm_Device *dev)
411{
412 if (!dev) return 0;
413 return dev->format;
414}
diff --git a/src/lib/ecore_drm/ecore_drm_device.c b/src/lib/ecore_drm/ecore_drm_device.c
new file mode 100644
index 0000000000..3fec7f659c
--- /dev/null
+++ b/src/lib/ecore_drm/ecore_drm_device.c
@@ -0,0 +1,583 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include "ecore_drm_private.h"
6#include <dlfcn.h>
7
8/* #ifdef HAVE_GBM */
9/* static Eina_Bool */
10/* _ecore_drm_device_egl_config_get(Ecore_Drm_Device *dev, const EGLint *attribs, const EGLint *visual) */
11/* { */
12/* EGLint c = 0, m = 0; */
13/* EGLConfig *cfgs; */
14/* int i = 0; */
15
16/* if (!eglGetConfigs(dev->egl.disp, NULL, 0, &c) || (c < 1)) */
17/* return EINA_FALSE; */
18
19/* if (!(cfgs = calloc(c, sizeof(*cfgs)))) return EINA_FALSE; */
20
21/* if (!eglChooseConfig(dev->egl.disp, attribs, cfgs, c, &m)) */
22/* { */
23/* free(cfgs); */
24/* return EINA_FALSE; */
25/* } */
26
27/* for (i = 0; i < m; i++) */
28/* { */
29/* EGLint id; */
30
31/* if (visual) */
32/* { */
33/* if (!eglGetConfigAttrib(dev->egl.disp, cfgs[i], */
34/* EGL_NATIVE_VISUAL_ID, &id)) */
35/* continue; */
36
37/* if ((id != 0) && (id != *visual)) */
38/* continue; */
39/* } */
40
41/* dev->egl.cfg = cfgs[i]; */
42/* free(cfgs); */
43/* return EINA_TRUE; */
44/* } */
45
46/* free(cfgs); */
47/* return EINA_FALSE; */
48/* } */
49/* #endif */
50
51static void
52_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)
53{
54 Ecore_Drm_Output *output;
55
56 DBG("Drm Page Flip Event");
57
58 if (!(output = data)) return;
59
60 if (output->pending_flip)
61 {
62 ecore_drm_output_fb_release(output, output->current);
63 output->current = output->next;
64 output->next = NULL;
65 }
66
67 output->pending_flip = EINA_FALSE;
68 if (!output->pending_vblank) ecore_drm_output_repaint(output);
69}
70
71static void
72_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)
73{
74 Ecore_Drm_Sprite *sprite;
75 Ecore_Drm_Output *output;
76
77 DBG("Drm VBlank Event");
78
79 if (!(sprite = data)) return;
80
81 output = sprite->output;
82 output->pending_vblank = EINA_FALSE;
83
84 ecore_drm_output_fb_release(output, sprite->current_fb);
85 sprite->current_fb = sprite->next_fb;
86 sprite->next_fb = NULL;
87
88 if (!output->pending_flip) _ecore_drm_output_frame_finish(output);
89}
90
91static Eina_Bool
92_ecore_drm_device_cb_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
93{
94 Ecore_Drm_Device *dev;
95 drmEventContext ctx;
96
97 if (!(dev = data)) return ECORE_CALLBACK_RENEW;
98
99 DBG("Drm Device Event");
100
101 memset(&ctx, 0, sizeof(ctx));
102
103 ctx.version = DRM_EVENT_CONTEXT_VERSION;
104 ctx.page_flip_handler = _ecore_drm_device_cb_page_flip;
105 ctx.vblank_handler = _ecore_drm_device_cb_vblank;
106
107 drmHandleEvent(dev->drm.fd, &ctx);
108
109 return ECORE_CALLBACK_RENEW;
110}
111
112static Eina_Bool
113_ecore_drm_device_cb_idle(void *data)
114{
115 Ecore_Drm_Device *dev;
116 Ecore_Drm_Output *output;
117 Eina_List *l;
118
119 if (!(dev = data)) return ECORE_CALLBACK_CANCEL;
120
121 EINA_LIST_FOREACH(dev->outputs, l, output)
122 {
123 output->need_repaint = EINA_TRUE;
124 if (output->repaint_scheduled) continue;
125 _ecore_drm_output_repaint_start(output);
126 }
127
128 return ECORE_CALLBACK_RENEW;
129}
130
131/**
132 * @defgroup Ecore_Drm_Device_Group Device manipulation functions
133 *
134 * Functions that deal with finding, opening, closing, and otherwise using
135 * the DRM device itself.
136 */
137
138/**
139 * Find a drm device in the system.
140 *
141 * @param name The name of the device to find. If NULL, this function will
142 * search for the default drm device.
143 * @param seat The name of the seat where this device may be found. If NULL,
144 * this function will use a default seat name 'seat0'.
145 *
146 * @return An opaque Ecore_Drm_Device structure representing the card.
147 *
148 * @ingroup Ecore_Drm_Device_Group
149 */
150EAPI Ecore_Drm_Device *
151ecore_drm_device_find(const char *name, const char *seat)
152{
153 Ecore_Drm_Device *dev = NULL;
154 struct udev_enumerate *uenum;
155 struct udev_list_entry *uentry;
156 struct udev_device *udevice, *tmpdevice = NULL, *pcidevice;
157 const char *path = NULL, *devseat = NULL;
158
159 /* check for existing udev reference */
160 if (!udev) return NULL;
161
162 /* setup udev enumerator */
163 uenum = udev_enumerate_new(udev);
164 udev_enumerate_add_match_subsystem(uenum, "drm");
165 udev_enumerate_add_match_subsystem(uenum, "card[0-9]*");
166
167 /* ask udev for list of drm devices */
168 udev_enumerate_scan_devices(uenum);
169
170 /* loop list of returned devices */
171 udev_list_entry_foreach(uentry, udev_enumerate_get_list_entry(uenum))
172 {
173 /* get device path */
174 path = udev_list_entry_get_name(uentry);
175
176 /* get udev device */
177 if (!(udevice = udev_device_new_from_syspath(udev, path)))
178 continue;
179
180 /* if we are looking for a certain device, then compare names */
181 if (name)
182 {
183 if (strcmp(name, udev_device_get_devnode(udevice)))
184 {
185 udev_device_unref(udevice);
186 continue;
187 }
188 }
189
190 /* get this devices' seat */
191 devseat = udev_device_get_property_value(udevice, "ID_SEAT");
192 if (!devseat) devseat = "seat0";
193
194 /* if we are looking for a device on a certain seat, compare it */
195 if (seat)
196 {
197 if (strcmp(seat, devseat))
198 {
199 udev_device_unref(udevice);
200 continue;
201 }
202 }
203 else
204 {
205 /* no seat name passed to use. check default */
206 if (strcmp(devseat, "seat0"))
207 {
208 udev_device_unref(udevice);
209 continue;
210 }
211 }
212
213 /* try to find the boot_vga attribute */
214 if ((pcidevice =
215 udev_device_get_parent_with_subsystem_devtype(udevice, "pci", NULL)))
216 {
217 const char *id;
218
219 if ((id = udev_device_get_sysattr_value(pcidevice, "boot_vga")))
220 {
221 if (!strcmp(id, "1"))
222 {
223 if (tmpdevice) udev_device_unref(tmpdevice);
224 tmpdevice = udevice;
225 break;
226 }
227 }
228 }
229
230 if (!tmpdevice)
231 tmpdevice = udevice;
232 else
233 udev_device_unref(udevice);
234 }
235
236 /* destroy the enumerator */
237 udev_enumerate_unref(uenum);
238
239 if (tmpdevice)
240 {
241 DBG("Found Drm Device");
242 DBG("\tFilename: %s", udev_device_get_devnode(tmpdevice));
243 DBG("\tDriver: %s", udev_device_get_driver(tmpdevice));
244 DBG("\tDevpath: %s", udev_device_get_devpath(tmpdevice));
245 DBG("\tSyspath: %s", udev_device_get_syspath(tmpdevice));
246 DBG("\tSysname: %s", udev_device_get_sysname(tmpdevice));
247
248 /* try to allocate space for return device structure */
249 if ((dev = calloc(1, sizeof(Ecore_Drm_Device))))
250 {
251 const char *id, *seat;
252
253 /* set device name */
254 dev->drm.name =
255 eina_stringshare_add(udev_device_get_devnode(tmpdevice));
256
257 /* set device path */
258 dev->drm.path =
259 eina_stringshare_add(udev_device_get_syspath(tmpdevice));
260
261 /* store id for this device */
262 if ((id = udev_device_get_sysnum(tmpdevice)))
263 dev->id = atoi(id);
264
265 /* set dev seat */
266 seat = udev_device_get_property_value(tmpdevice, "ID_SEAT");
267 if (!seat) seat = "seat0";
268
269 dev->seat = eina_stringshare_add(seat);
270
271 dev->format = GBM_FORMAT_XRGB8888;
272 dev->use_hw_accel = EINA_FALSE;
273 }
274 }
275
276 /* release device reference */
277 udev_device_unref(tmpdevice);
278
279 return dev;
280}
281
282/**
283 * Free an Ecore_Drm_Device
284 *
285 * This function will cleanup and free any previously allocated Ecore_Drm_Device.
286 *
287 * @param dev The Ecore_Drm_Device to free
288 *
289 * @ingroup Ecore_Drm_Device_Group
290 */
291EAPI void
292ecore_drm_device_free(Ecore_Drm_Device *dev)
293{
294 Ecore_Drm_Output *output;
295
296 /* check for valid device */
297 if (!dev) return;
298
299 /* free outputs */
300 EINA_LIST_FREE(dev->outputs, output)
301 ecore_drm_output_free(output);
302
303 /* free crtcs */
304 if (dev->crtcs) free(dev->crtcs);
305
306 /* free device name */
307 if (dev->drm.name) eina_stringshare_del(dev->drm.name);
308
309 /* free device path */
310 if (dev->drm.path) eina_stringshare_del(dev->drm.path);
311
312 /* free device seat */
313 if (dev->seat) eina_stringshare_del(dev->seat);
314
315 /* free structure */
316 free(dev);
317}
318
319/**
320 * Open an Ecore_Drm_Device
321 *
322 * This function will open an existing Ecore_Drm_Device for use.
323 *
324 * @param dev The Ecore_Drm_Device to try and open
325 *
326 * @return EINA_TRUE on success, EINA_FALSE on failure
327 *
328 * @ingroup Ecore_Drm_Device_Group
329 */
330EAPI Eina_Bool
331ecore_drm_device_open(Ecore_Drm_Device *dev)
332{
333 uint64_t caps;
334
335 /* check for valid device */
336 if ((!dev) || (!dev->drm.name)) return EINA_FALSE;
337
338 dev->drm.fd = open(dev->drm.name, O_RDWR);
339 if (dev->drm.fd < 0) return EINA_FALSE;
340
341 DBG("Opened Device %s : %d", dev->drm.name, dev->drm.fd);
342
343 if (!drmGetCap(dev->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &caps))
344 {
345 if (caps == 1)
346 dev->drm.clock = CLOCK_MONOTONIC;
347 else
348 dev->drm.clock = CLOCK_REALTIME;
349 }
350 else
351 {
352 ERR("Could not get device capabilities: %m");
353 }
354
355/* #ifdef HAVE_GBM */
356/* if (getenv("ECORE_DRM_HW_ACCEL")) */
357/* { */
358 /* Typically, gbm loads the dri driver However some versions of Mesa
359 * do not have libglapi symbols linked in the driver. Because of this,
360 * using hardware accel for our drm code Could fail with a
361 * message that the driver could not load. Let's be proactive and
362 * work around this for the user by preloading the glapi library */
363 /* dlopen("libglapi.so.0", (RTLD_LAZY | RTLD_GLOBAL)); */
364
365 /* if ((dev->gbm = gbm_create_device(dev->drm.fd))) */
366 /* { */
367 /* EGLint major, minor, visual; */
368 /* const EGLint attribs[] = */
369 /* { */
370 /* EGL_SURFACE_TYPE, EGL_WINDOW_BIT, */
371 /* EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, */
372 /* EGL_BLUE_SIZE, 1, EGL_ALPHA_SIZE, 0, */
373 /* EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE */
374 /* }; */
375
376 /* dev->use_hw_accel = EINA_TRUE; */
377 /* dev->format = GBM_FORMAT_XRGB8888; */
378
379 /* dev->egl.disp = eglGetDisplay(dev->gbm); */
380 /* if (dev->egl.disp == EGL_NO_DISPLAY) */
381 /* { */
382 /* ERR("Could not get egl display"); */
383 /* goto init_software; */
384 /* } */
385
386 /* if (!eglInitialize(dev->egl.disp, &major, &minor)) */
387 /* { */
388 /* ERR("Could not initialize egl"); */
389 /* goto init_software; */
390 /* } */
391
392 /* visual = dev->format; */
393 /* if (!_ecore_drm_device_egl_config_get(dev, attribs, &visual)) */
394 /* { */
395 /* ERR("Could not get egl config"); */
396 /* goto init_software; */
397 /* } */
398 /* } */
399 /* else */
400 /* { */
401 /* WRN("Failed to create gbm device"); */
402 /* goto init_software; */
403 /* } */
404 /* } */
405 /* else */
406/* #endif */
407 /* { */
408 /* TODO: init software */
409/* init_software: */
410/* DBG("Init Software Engine"); */
411/* #ifdef HAVE_GBM */
412/* if (dev->egl.disp) */
413/* { */
414/* eglMakeCurrent(dev->egl.disp, EGL_NO_SURFACE, EGL_NO_SURFACE, */
415/* EGL_NO_CONTEXT); */
416/* eglTerminate(dev->egl.disp); */
417/* eglReleaseThread(); */
418/* } */
419
420/* if (dev->gbm) gbm_device_destroy(dev->gbm); */
421/* dev->gbm = NULL; */
422/* #endif */
423/* } */
424
425 dev->drm.hdlr =
426 ecore_main_fd_handler_add(dev->drm.fd, ECORE_FD_READ,
427 _ecore_drm_device_cb_event, dev, NULL, NULL);
428
429 dev->drm.idler =
430 ecore_idle_enterer_add(_ecore_drm_device_cb_idle, dev);
431
432 return EINA_TRUE;
433}
434
435/**
436 * Close an Ecore_Drm_Device
437 *
438 * This function will close a previously opened Ecore_Drm_Device
439 *
440 * @param dev The Ecore_Drm_Device to free
441 *
442 * @return EINA_TRUE on success, EINA_FALSE on failure
443 *
444 * @ingroup Ecore_Drm_Device_Group
445 */
446EAPI Eina_Bool
447ecore_drm_device_close(Ecore_Drm_Device *dev)
448{
449 /* check for valid device */
450 if (!dev) return EINA_FALSE;
451
452/* #ifdef HAVE_GBM */
453/* if (dev->use_hw_accel) */
454/* { */
455/* if (dev->egl.disp) */
456/* { */
457/* eglMakeCurrent(dev->egl.disp, EGL_NO_SURFACE, EGL_NO_SURFACE, */
458/* EGL_NO_CONTEXT); */
459/* eglTerminate(dev->egl.disp); */
460/* eglReleaseThread(); */
461/* } */
462
463/* if (dev->gbm) gbm_device_destroy(dev->gbm); */
464/* dev->gbm = NULL; */
465/* } */
466/* #endif */
467
468 if (dev->drm.hdlr) ecore_main_fd_handler_del(dev->drm.hdlr);
469 dev->drm.hdlr = NULL;
470
471 close(dev->drm.fd);
472
473 /* reset device fd */
474 dev->drm.fd = -1;
475
476 /* free(data); */
477
478 return EINA_TRUE;
479}
480
481/**
482 * Get if a given Ecore_Drm_Device is master
483 *
484 * This function will check if the given drm device is set to master
485 *
486 * @param dev The Ecore_Drm_Device to check
487 *
488 * @return EINA_TRUE if device is master, EINA_FALSE otherwise
489 *
490 * @ingroup Ecore_Drm_Device_Group
491 */
492EAPI Eina_Bool
493ecore_drm_device_master_get(Ecore_Drm_Device *dev)
494{
495 /* drm_magic_t mag; */
496
497 /* check for valid device */
498 if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
499
500 /* FIXME: Remote this to the slave process !! */
501
502 /* get if we are master or not */
503 /* if ((drmGetMagic(dev->drm.fd, &mag) == 0) && */
504 /* (drmAuthMagic(dev->drm.fd, mag) == 0)) */
505 /* return EINA_TRUE; */
506
507 return EINA_FALSE;
508}
509
510/**
511 * Set a given Ecore_Drm_Device to master
512 *
513 * This function will attempt to set a given drm device to be master
514 *
515 * @param dev The Ecore_Drm_Device to set
516 *
517 * @return EINA_TRUE on success, EINA_FALSE on failure
518 *
519 * @ingroup Ecore_Drm_Device_Group
520 */
521EAPI Eina_Bool
522ecore_drm_device_master_set(Ecore_Drm_Device *dev)
523{
524 Eina_Bool ret = EINA_FALSE;
525 int dfd;
526
527 /* check for valid device */
528 if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
529
530 DBG("Set Master On Fd: %d", dev->drm.fd);
531
532 /* try to close the device */
533 _ecore_drm_message_send(ECORE_DRM_OP_DEVICE_MASTER_SET, dev->drm.fd,
534 NULL, 0);
535
536 /* get the result of the close operation */
537 ret = _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_MASTER_SET, &dfd,
538 NULL, 0);
539 if (!ret) return EINA_FALSE;
540
541 return EINA_TRUE;
542}
543
544/**
545 * Tell a given Ecore_Drm_Device to stop being master
546 *
547 * This function will attempt to ask a drm device to stop being master
548 *
549 * @param dev The Ecore_Drm_Device to set
550 *
551 * @return EINA_TRUE on success, EINA_FALSE on failure
552 *
553 * @ingroup Ecore_Drm_Device_Group
554 */
555EAPI Eina_Bool
556ecore_drm_device_master_drop(Ecore_Drm_Device *dev)
557{
558 Eina_Bool ret = EINA_FALSE;
559 int dfd;
560
561 /* check for valid device */
562 if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
563
564 DBG("Drop Master On Fd: %d", dev->drm.fd);
565
566 /* try to close the device */
567 _ecore_drm_message_send(ECORE_DRM_OP_DEVICE_MASTER_DROP, dev->drm.fd,
568 NULL, 0);
569
570 /* get the result of the close operation */
571 ret = _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_MASTER_DROP, &dfd,
572 NULL, 0);
573 if (!ret) return EINA_FALSE;
574
575 return EINA_TRUE;
576}
577
578EAPI int
579ecore_drm_device_fd_get(Ecore_Drm_Device *dev)
580{
581 if (!dev) return -1;
582 return dev->drm.fd;
583}
diff --git a/src/lib/ecore_drm/ecore_drm_evdev.c b/src/lib/ecore_drm/ecore_drm_evdev.c
new file mode 100644
index 0000000000..0e5e840056
--- /dev/null
+++ b/src/lib/ecore_drm/ecore_drm_evdev.c
@@ -0,0 +1,360 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5/* copied from udev/extras/input_id/input_id.c */
6/* we must use this kernel-compatible implementation */
7#define BITS_PER_LONG (sizeof(unsigned long) * 8)
8#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
9#define OFF(x) ((x)%BITS_PER_LONG)
10#define BIT(x) (1UL<<OFF(x))
11#define LONG(x) ((x)/BITS_PER_LONG)
12#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
13/* end copied */
14
15#include "ecore_drm_private.h"
16#include <sys/ioctl.h>
17#include <linux/input.h>
18
19/* local functions */
20static Eina_Bool
21_device_configure(Ecore_Drm_Evdev *edev)
22{
23 Eina_Bool ret = EINA_FALSE;
24
25 if (!edev) return EINA_FALSE;
26
27 if ((edev->caps & (EVDEV_MOTION_ABS | EVDEV_MOTION_REL)) &&
28 (edev->caps & EVDEV_BUTTON))
29 {
30 DBG("Input device %s is a pointer", edev->name);
31 edev->seat_caps |= EVDEV_SEAT_POINTER;
32 ret = EINA_TRUE;
33 }
34
35 if (edev->caps & EVDEV_KEYBOARD)
36 {
37 DBG("Input device %s is a keyboard", edev->name);
38 edev->seat_caps |= EVDEV_SEAT_KEYBOARD;
39 ret = EINA_TRUE;
40 }
41
42 if (edev->caps & EVDEV_TOUCH)
43 {
44 DBG("Input device %s is a touchpad", edev->name);
45 edev->seat_caps |= EVDEV_SEAT_TOUCH;
46 ret = EINA_TRUE;
47 }
48
49 return ret;
50}
51
52static Eina_Bool
53_device_handle(Ecore_Drm_Evdev *edev)
54{
55 struct input_absinfo absinfo;
56 unsigned long dev_bits[NBITS(EV_MAX)];
57 unsigned long abs_bits[NBITS(ABS_MAX)];
58 unsigned long rel_bits[NBITS(REL_MAX)];
59 unsigned long key_bits[NBITS(KEY_MAX)];
60 /* Eina_Bool have_key = EINA_FALSE; */
61 Eina_Bool have_abs = EINA_FALSE;
62
63 if (!edev) return EINA_FALSE;
64
65 ioctl(edev->fd, EVIOCGBIT(0, sizeof(dev_bits)), dev_bits);
66 if (TEST_BIT(dev_bits, EV_ABS))
67 {
68 have_abs = EINA_TRUE;
69
70 ioctl(edev->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
71
72 if ((TEST_BIT(abs_bits, ABS_WHEEL)) ||
73 (TEST_BIT(abs_bits, ABS_GAS)) ||
74 (TEST_BIT(abs_bits, ABS_BRAKE)) ||
75 (TEST_BIT(abs_bits, ABS_HAT0X)))
76 {
77 /* ignore joystick */
78 return EINA_FALSE;
79 }
80
81 if (TEST_BIT(abs_bits, ABS_X))
82 {
83 ioctl(edev->fd, EVIOCGABS(ABS_X), &absinfo);
84 edev->abs.min_x = absinfo.minimum;
85 edev->abs.max_x = absinfo.maximum;
86 edev->caps |= EVDEV_MOTION_ABS;
87 }
88
89 if (TEST_BIT(abs_bits, ABS_Y))
90 {
91 ioctl(edev->fd, EVIOCGABS(ABS_Y), &absinfo);
92 edev->abs.min_y = absinfo.minimum;
93 edev->abs.max_y = absinfo.maximum;
94 edev->caps |= EVDEV_MOTION_ABS;
95 }
96
97 if ((TEST_BIT(abs_bits, ABS_MT_POSITION_X)) &&
98 (TEST_BIT(abs_bits, ABS_MT_POSITION_Y)))
99 {
100 DBG("Handle MultiTouch Device: %s", edev->path);
101 }
102 }
103
104 if (TEST_BIT(dev_bits, EV_REL))
105 {
106 ioctl(edev->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits);
107
108 if ((TEST_BIT(rel_bits, REL_X)) || (TEST_BIT(rel_bits, REL_Y)))
109 edev->caps |= EVDEV_MOTION_REL;
110 }
111
112 if (TEST_BIT(dev_bits, EV_KEY))
113 {
114 unsigned int i = 0;
115
116 /* have_key = EINA_TRUE; */
117
118 ioctl(edev->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits);
119
120 if (have_abs)
121 {
122 if ((TEST_BIT(key_bits, BTN_TOOL_FINGER)) &&
123 (!TEST_BIT(key_bits, BTN_TOOL_PEN)))
124 {
125 DBG("Device Is Touchpad: %s", edev->path);
126 }
127 }
128
129 for (i = KEY_ESC; i < KEY_MAX; i++)
130 {
131 if ((i >= BTN_MISC) && (i < KEY_OK)) continue;
132 if (TEST_BIT(key_bits, i))
133 {
134 edev->caps |= EVDEV_KEYBOARD;
135 break;
136 }
137 }
138
139 if (TEST_BIT(key_bits, BTN_TOUCH))
140 edev->caps |= EVDEV_TOUCH;
141
142 for (i = BTN_MISC; i < BTN_JOYSTICK; i++)
143 {
144 if (TEST_BIT(key_bits, i))
145 {
146 edev->caps |= EVDEV_BUTTON;
147 edev->caps &= ~EVDEV_TOUCH;
148 break;
149 }
150 }
151 }
152
153 if (TEST_BIT(dev_bits, EV_LED)) edev->caps |= EVDEV_KEYBOARD;
154
155 return EINA_TRUE;
156}
157
158static void
159_device_notify_key(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
160{
161 DBG("Key Event");
162 DBG("\tCode: %d", event->code);
163 DBG("\tValue: %d", event->value);
164
165 if ((event->code >= KEY_ESC) && (event->code <= KEY_COMPOSE))
166 {
167 /* ignore key repeat */
168 if (event->value == 2)
169 {
170 DBG("\tKey Repeat");
171 }
172 }
173}
174
175static void
176_device_process_flush(Ecore_Drm_Evdev *dev, unsigned int timestamp)
177{
178 switch (dev->pending_event)
179 {
180 case EVDEV_NONE:
181 return;
182 case EVDEV_RELATIVE_MOTION:
183 goto out;
184 break;
185 case EVDEV_ABSOLUTE_MT_DOWN:
186 goto out;
187 break;
188 case EVDEV_ABSOLUTE_MT_MOTION:
189 goto out;
190 break;
191 case EVDEV_ABSOLUTE_MT_UP:
192 goto out;
193 break;
194 case EVDEV_ABSOLUTE_TOUCH_DOWN:
195 goto out;
196 break;
197 case EVDEV_ABSOLUTE_MOTION:
198 goto out;
199 break;
200 case EVDEV_ABSOLUTE_TOUCH_UP:
201 goto out;
202 break;
203 }
204
205out:
206 dev->pending_event = EVDEV_NONE;
207}
208
209static void
210_device_process_key(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
211{
212 if (event->code == BTN_TOUCH)
213 {
214 /* TODO: check for mt device */
215 return;
216 }
217
218 _device_process_flush(dev, timestamp);
219
220 switch (event->code)
221 {
222 case BTN_LEFT:
223 case BTN_RIGHT:
224 case BTN_MIDDLE:
225 case BTN_SIDE:
226 case BTN_EXTRA:
227 case BTN_FORWARD:
228 case BTN_BACK:
229 case BTN_TASK:
230 /* TODO: notify button */
231 break;
232 default:
233 _device_notify_key(dev, event, timestamp);
234 break;
235 }
236}
237
238static void
239_device_process(Ecore_Drm_Evdev *dev, struct input_event *event, int count)
240{
241 struct input_event *ev, *end;
242 unsigned int timestamp = 0;
243
244 DBG("Evdev Device Process");
245
246 ev = event;
247 end = ev + count;
248 for (ev = event; ev < end; ev++)
249 {
250 timestamp = (ev->time.tv_sec * 1000) + (ev->time.tv_usec / 1000);
251
252 switch (ev->type)
253 {
254 case EV_KEY:
255 _device_process_key(dev, ev, timestamp);
256 break;
257 case EV_REL:
258 DBG("\tRelative Event");
259 break;
260 case EV_ABS:
261 DBG("\tAbsolute Event");
262 break;
263 case EV_SYN:
264 _device_process_flush(dev, timestamp);
265 break;
266 default:
267 break;
268 }
269 }
270}
271
272static Eina_Bool
273_cb_device_data(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
274{
275 Ecore_Drm_Evdev *edev;
276 struct input_event ev[32];
277 int len = 0;
278
279 if (!(edev = data)) return EINA_TRUE;
280
281 do
282 {
283 len = read(edev->fd, &ev, sizeof(ev));
284
285 if ((len < 0) || ((len % sizeof(ev[0])) != 0))
286 {
287 if ((len < 0) && (errno != EAGAIN) && (errno != EINTR))
288 {
289 ERR("Device Died");
290 }
291
292 return EINA_TRUE;
293 }
294
295 edev->event_process(edev, ev, (len / sizeof(ev[0])));
296
297 } while (len > 0);
298
299 return EINA_TRUE;
300}
301
302/* external functions */
303Ecore_Drm_Evdev *
304_ecore_drm_evdev_device_create(Ecore_Drm_Seat *seat, const char *path, int fd)
305{
306 Ecore_Drm_Evdev *edev;
307 char name[256] = "unknown";
308
309 if (!(edev = calloc(1, sizeof(Ecore_Drm_Evdev))))
310 return NULL;
311
312 edev->seat = seat;
313 edev->path = eina_stringshare_add(path);
314 edev->fd = fd;
315
316 if (ioctl(edev->fd, EVIOCGNAME(sizeof(name)), name) < 0)
317 DBG("Error getting device name: %m");
318
319 name[sizeof(name) - 1] = '\0';
320 edev->name = eina_stringshare_add(name);
321
322 if (!_device_handle(edev))
323 {
324 ERR("Unhandled Input Device: %s", name);
325 _ecore_drm_evdev_device_destroy(edev);
326 return NULL;
327 }
328
329 if (!_device_configure(edev))
330 {
331 _ecore_drm_evdev_device_destroy(edev);
332 return NULL;
333 }
334
335 edev->event_process = _device_process;
336
337 edev->hdlr =
338 ecore_main_fd_handler_add(edev->fd, ECORE_FD_READ,
339 _cb_device_data, edev, NULL, NULL);
340 if (!edev->hdlr)
341 {
342 ERR("Could not create fd handler");
343 _ecore_drm_evdev_device_destroy(edev);
344 return NULL;
345 }
346
347 return edev;
348}
349
350void
351_ecore_drm_evdev_device_destroy(Ecore_Drm_Evdev *dev)
352{
353 if (!dev) return;
354
355 if (dev->path) eina_stringshare_del(dev->path);
356 if (dev->name) eina_stringshare_del(dev->name);
357 if (dev->hdlr) ecore_main_fd_handler_del(dev->hdlr);
358
359 free(dev);
360}
diff --git a/src/lib/ecore_drm/ecore_drm_fb.c b/src/lib/ecore_drm/ecore_drm_fb.c
new file mode 100644
index 0000000000..40dd473ed9
--- /dev/null
+++ b/src/lib/ecore_drm/ecore_drm_fb.c
@@ -0,0 +1,151 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "ecore_drm_private.h"
6
7/**
8 * @defgroup Ecore_Drm_Fb_Group
9 *
10 */
11
12/* TODO: DOXY !! */
13
14EAPI Ecore_Drm_Fb *
15ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height)
16{
17 Ecore_Drm_Fb *fb;
18 struct drm_mode_create_dumb carg;
19 struct drm_mode_destroy_dumb darg;
20 struct drm_mode_map_dumb marg;
21
22 if (!(fb = calloc(1, sizeof(Ecore_Drm_Fb)))) return NULL;
23
24 memset(&carg, 0, sizeof(struct drm_mode_create_dumb));
25
26 carg.bpp = 32; // FIXME: Hard-coded depth
27 carg.width = width;
28 carg.height = height;
29
30 if (drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg))
31 {
32 ERR("Could not create dumb framebuffer: %m");
33 goto create_err;
34 }
35
36 fb->from_client = EINA_TRUE;
37 fb->hdl = carg.handle;
38 fb->stride = carg.pitch;
39 fb->size = carg.size;
40 fb->fd = dev->drm.fd;
41
42 if (drmModeAddFB(dev->drm.fd, width, height, 24, 32,
43 fb->stride, fb->hdl, &fb->id))
44 {
45 ERR("Could not add framebuffer: %m");
46 goto add_err;
47 }
48
49 memset(&marg, 0, sizeof(struct drm_mode_map_dumb));
50 marg.handle = fb->hdl;
51 if (drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_MAP_DUMB, &marg))
52 {
53 ERR("Could not map framebuffer: %m");
54 goto map_err;
55 }
56
57 fb->mmap =
58 mmap(0, fb->size, PROT_WRITE | PROT_READ, MAP_SHARED,
59 dev->drm.fd, marg.offset);
60 if (fb->mmap == MAP_FAILED)
61 {
62 ERR("Could not mmap framebuffer space: %m");
63 goto map_err;
64 }
65
66 memset(fb->mmap, 0, fb->size);
67
68 return fb;
69
70map_err:
71 drmModeRmFB(fb->fd, fb->id);
72add_err:
73 memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
74 darg.handle = fb->hdl;
75 drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
76create_err:
77 free(fb);
78 return NULL;
79}
80
81EAPI void
82ecore_drm_fb_destroy(Ecore_Drm_Fb *fb)
83{
84 struct drm_mode_destroy_dumb darg;
85
86 if ((!fb) || (!fb->mmap)) return;
87
88 if (fb->id) drmModeRmFB(fb->fd, fb->id);
89 munmap(fb->mmap, fb->size);
90 memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
91 darg.handle = fb->hdl;
92 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
93 free(fb);
94}
95
96/* #ifdef HAVE_GBM */
97/* static void */
98/* _ecore_drm_fb_user_data_destroy(struct gbm_bo *bo EINA_UNUSED, void *data) */
99/* { */
100/* Ecore_Drm_Fb *fb; */
101
102/* if (!(fb = data)) return; */
103/* ecore_drm_fb_destroy(fb); */
104/* } */
105
106/* Ecore_Drm_Fb * */
107/* _ecore_drm_fb_bo_get(Ecore_Drm_Device *dev, struct gbm_bo *bo) */
108/* { */
109/* Ecore_Drm_Fb *fb; */
110/* unsigned int width, height; */
111/* unsigned int h[4], p[4], o[4]; */
112/* int ret = -1; */
113
114/* if ((fb = gbm_bo_get_user_data(bo))) return fb; */
115
116/* if (!(fb = calloc(1, sizeof(Ecore_Drm_Fb)))) return NULL; */
117
118/* fb->bo = bo; */
119
120/* width = gbm_bo_get_width(bo); */
121/* height = gbm_bo_get_height(bo); */
122/* fb->stride = gbm_bo_get_stride(bo); */
123/* fb->hdl = gbm_bo_get_handle(bo).u32; */
124/* fb->size = (fb->stride * height); */
125/* fb->fd = dev->drm.fd; */
126
127/* h[0] = fb->hdl; */
128/* p[0] = fb->stride; */
129/* o[0] = 0; */
130
131/* ret = drmModeAddFB2(dev->drm.fd, width, height, dev->format, h, p, o, */
132/* &fb->id, 0); */
133/* if (ret) */
134/* { */
135/* ret = drmModeAddFB(dev->drm.fd, width, height, 24, 32, */
136/* fb->stride, fb->hdl, &fb->id); */
137
138/* } */
139
140/* if (ret) */
141/* { */
142/* ERR("Error during ModeAddFb"); */
143/* free(fb); */
144/* return NULL; */
145/* } */
146
147/* gbm_bo_set_user_data(bo, fb, _ecore_drm_fb_user_data_destroy); */
148
149/* return fb; */
150/* } */
151/* #endif */
diff --git a/src/lib/ecore_drm/ecore_drm_inputs.c b/src/lib/ecore_drm/ecore_drm_inputs.c
new file mode 100644
index 0000000000..c511d86656
--- /dev/null
+++ b/src/lib/ecore_drm/ecore_drm_inputs.c
@@ -0,0 +1,303 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "ecore_drm_private.h"
6
7/* local functions */
8static Ecore_Drm_Seat *
9_seat_get(Ecore_Drm_Input *input, const char *seat)
10{
11 Ecore_Drm_Seat *s;
12 Eina_List *l;
13
14 EINA_LIST_FOREACH(input->dev->seats, l, s)
15 {
16 if (!strcmp(s->name, seat)) return s;
17 }
18
19 if (!(s = calloc(1, sizeof(Ecore_Drm_Seat))))
20 return NULL;
21
22 s->input = input;
23 s->name = eina_stringshare_add(seat);
24
25 input->dev->seats = eina_list_append(input->dev->seats, s);
26
27 return s;
28}
29
30static Eina_Bool
31_device_add(Ecore_Drm_Input *input, struct udev_device *device)
32{
33 Ecore_Drm_Evdev *edev;
34 Ecore_Drm_Seat *seat;
35 const char *dev_seat, *wl_seat;
36 const char *node;
37 char n[PATH_MAX];
38 int fd = -1;
39
40 if (!(dev_seat = udev_device_get_property_value(device, "ID_SEAT")))
41 dev_seat = "seat0";
42
43 if (strcmp(dev_seat, input->seat)) return EINA_FALSE;
44
45 if (!(wl_seat = udev_device_get_property_value(device, "WL_SEAT")))
46 wl_seat = "seat0";
47
48 if (!(seat = _seat_get(input, wl_seat)))
49 return EINA_FALSE;
50
51 node = udev_device_get_devnode(device);
52 strcpy(n, node);
53 fd = open(n, O_RDWR | O_NONBLOCK);
54 /* _ecore_drm_message_send(ECORE_DRM_OP_DEVICE_OPEN, -1, n, strlen(n)); */
55 /* _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_OPEN, &fd, NULL, 0); */
56 /* DBG("Opened Restricted Input: %s %d", node, fd); */
57
58 if (!(edev = _ecore_drm_evdev_device_create(seat, node, fd)))
59 {
60 close(fd);
61 /* _ecore_drm_message_send(ECORE_DRM_OP_DEVICE_CLOSE, fd, NULL, 0); */
62 /* _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_OPEN, &fd, NULL, 0); */
63 return EINA_FALSE;
64 }
65
66 seat->devices = eina_list_append(seat->devices, edev);
67
68 /* TODO: finish */
69
70 return EINA_TRUE;
71}
72
73static void
74_device_remove(Ecore_Drm_Input *input, const char *device)
75{
76 Ecore_Drm_Seat *seat;
77 Eina_List *l;
78
79 if (!input) return;
80
81 EINA_LIST_FOREACH(input->dev->seats, l, seat)
82 {
83 Ecore_Drm_Evdev *edev;
84 Eina_List *ll;
85
86 EINA_LIST_FOREACH(seat->devices, ll, edev)
87 {
88 if (!strcmp(edev->path, device))
89 {
90 seat->devices = eina_list_remove(seat->devices, edev);
91 _ecore_drm_evdev_device_destroy(edev);
92 break;
93 }
94 }
95 }
96}
97
98static Eina_Bool
99_cb_input_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
100{
101 Ecore_Drm_Input *input;
102 struct udev_device *udevice;
103 const char *act;
104
105 DBG("Input Event");
106
107 if (!(input = data)) return EINA_FALSE;
108
109 if (!(udevice = udev_monitor_receive_device(input->monitor)))
110 return EINA_TRUE;
111
112 if (!(act = udev_device_get_action(udevice))) return EINA_TRUE;
113
114 if (strncmp("event", udev_device_get_sysname(udevice), 5) != 0)
115 goto err;
116
117 if (!strcmp(act, "add"))
118 {
119 DBG("\tDevice Added");
120 _device_add(input, udevice);
121 }
122 else if (!strcmp(act, "remove"))
123 {
124 const char *node;
125
126 node = udev_device_get_devnode(udevice);
127
128 DBG("\tDevice Removed: %s", node);
129 _device_remove(input, node);
130 }
131
132 return EINA_TRUE;
133
134err:
135 if (udevice) udev_device_unref(udevice);
136 return EINA_TRUE;
137}
138
139static Eina_Bool
140_devices_add(Ecore_Drm_Input *input)
141{
142 struct udev_enumerate *uenum;
143 struct udev_list_entry *uentry;
144 struct udev_device *udevice;
145 const char *path, *name;
146 Eina_Bool found = EINA_FALSE;
147
148 uenum = udev_enumerate_new(udev);
149 udev_enumerate_add_match_subsystem(uenum, "input");
150 udev_enumerate_scan_devices(uenum);
151
152 udev_list_entry_foreach(uentry, udev_enumerate_get_list_entry(uenum))
153 {
154 path = udev_list_entry_get_name(uentry);
155 udevice = udev_device_new_from_syspath(udev, path);
156 name = udev_device_get_sysname(udevice);
157
158 if (strncmp("event", name, 5) != 0)
159 {
160 udev_device_unref(udevice);
161 continue;
162 }
163
164 if (!_device_add(input, udevice))
165 {
166 udev_device_unref(udevice);
167 continue;
168 }
169
170 found = EINA_TRUE;
171
172 udev_device_unref(udevice);
173 }
174
175 udev_enumerate_unref(uenum);
176
177 if (!found)
178 {
179 ERR("No Input Devices Found");
180 return EINA_FALSE;
181 }
182
183 return EINA_TRUE;
184}
185
186/* public functions */
187EAPI Eina_Bool
188ecore_drm_inputs_create(Ecore_Drm_Device *dev)
189{
190 Ecore_Drm_Input *input;
191
192 /* check for valid device */
193 if ((!dev) || (!udev)) return EINA_FALSE;
194
195 /* try to allocate space for input structure */
196 if (!(input = calloc(1, sizeof(Ecore_Drm_Input))))
197 return EINA_FALSE;
198
199 /* FIXME: Hardcoded seat name */
200 input->seat = eina_stringshare_add("seat0");
201 input->dev = dev;
202
203 /* try to enable this input */
204 if (!ecore_drm_inputs_enable(input))
205 {
206 ERR("Could not enable input");
207 if (input->seat) eina_stringshare_del(input->seat);
208 free(input);
209 return EINA_FALSE;
210 }
211
212 /* add this input to dev */
213 dev->inputs = eina_list_append(dev->inputs, input);
214
215 return EINA_TRUE;
216}
217
218EAPI void
219ecore_drm_inputs_destroy(Ecore_Drm_Device *dev)
220{
221 Ecore_Drm_Seat *seat;
222 Eina_List *l;
223
224 if (!dev) return;
225
226 EINA_LIST_FOREACH(dev->seats, l, seat)
227 {
228 Ecore_Drm_Evdev *edev;
229
230 EINA_LIST_FREE(seat->devices, edev)
231 _ecore_drm_evdev_device_destroy(edev);
232 }
233}
234
235EAPI Eina_Bool
236ecore_drm_inputs_enable(Ecore_Drm_Input *input)
237{
238 /* check for valid input */
239 if (!input) return EINA_FALSE;
240
241 if (!input->monitor)
242 input->monitor = udev_monitor_new_from_netlink(udev, "udev");
243
244 if (!input->monitor)
245 {
246 ERR("Could not create udev monitor: %m");
247 return EINA_FALSE;
248 }
249
250 /* setup input filter */
251 udev_monitor_filter_add_match_subsystem_devtype(input->monitor,
252 "input", NULL);
253
254 /* try to enable receiving udev events */
255 if (udev_monitor_enable_receiving(input->monitor))
256 {
257 ERR("Could not bind udev monitor: %m");
258 udev_monitor_unref(input->monitor);
259 return EINA_FALSE;
260 }
261
262 /* save the fd */
263 if ((input->fd = udev_monitor_get_fd(input->monitor)) < 0)
264 {
265 ERR("Input monitor has no fd: %m");
266 udev_monitor_unref(input->monitor);
267 return EINA_FALSE;
268 }
269
270 /* create fd handler */
271 if (!input->hdlr)
272 {
273 input->hdlr =
274 ecore_main_fd_handler_add(input->fd, ECORE_FD_READ,
275 _cb_input_event, input, NULL, NULL);
276 }
277
278 if (!input->hdlr)
279 {
280 ERR("Failed to setup input fd handler: %m");
281 udev_monitor_unref(input->monitor);
282 return EINA_FALSE;
283 }
284
285 /* try to add devices */
286 if (!_devices_add(input))
287 {
288 ERR("Could not add input devices");
289 udev_monitor_unref(input->monitor);
290 return EINA_FALSE;
291 }
292
293 input->enabled = EINA_TRUE;
294 input->suspended = EINA_FALSE;
295
296 return EINA_TRUE;
297}
298
299EAPI void
300ecore_drm_inputs_disable(Ecore_Drm_Input *input)
301{
302 if (!input) return;
303}
diff --git a/src/lib/ecore_drm/ecore_drm_output.c b/src/lib/ecore_drm/ecore_drm_output.c
new file mode 100644
index 0000000000..f55e1f1f34
--- /dev/null
+++ b/src/lib/ecore_drm/ecore_drm_output.c
@@ -0,0 +1,703 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include "ecore_drm_private.h"
6
7#define ALEN(array) (sizeof(array) / sizeof(array)[0])
8
9static const char *conn_types[] =
10{
11 "None", "VGA", "DVI", "DVI", "DVI",
12 "Composite", "TV", "LVDS", "CTV", "DIN",
13 "DP", "HDMI", "HDMI", "TV", "eDP",
14};
15
16/* local functions */
17/* #ifdef HAVE_GBM */
18/* static Eina_Bool */
19/* _ecore_drm_output_context_create(Ecore_Drm_Device *dev, EGLSurface surface) */
20/* { */
21/* EGLBoolean r; */
22/* static const EGLint attribs[] = */
23/* { */
24/* EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE */
25/* }; */
26
27/* if ((!dev->egl.disp) || (!dev->egl.cfg)) return EINA_FALSE; */
28
29/* if (!eglBindAPI(EGL_OPENGL_ES_API)) */
30/* { */
31/* ERR("Could not bind egl api"); */
32/* return EINA_FALSE; */
33/* } */
34
35/* dev->egl.ctxt = */
36/* eglCreateContext(dev->egl.disp, dev->egl.cfg, EGL_NO_CONTEXT, attribs); */
37/* if (!dev->egl.ctxt) */
38/* { */
39/* ERR("Could not create Egl Context"); */
40/* return EINA_FALSE; */
41/* } */
42
43/* r = eglMakeCurrent(dev->egl.disp, surface, surface, dev->egl.ctxt); */
44/* if (r == EGL_FALSE) */
45/* { */
46/* ERR("Could not make surface current"); */
47/* return EINA_FALSE; */
48/* } */
49
50/* return EINA_TRUE; */
51/* } */
52
53/* static Eina_Bool */
54/* _ecore_drm_output_hardware_setup(Ecore_Drm_Device *dev, Ecore_Drm_Output *output) */
55/* { */
56/* unsigned int i = 0; */
57/* int flags = 0; */
58/* int w = 0, h = 0; */
59
60/* if ((!dev) || (!output)) return EINA_FALSE; */
61
62/* if (output->current_mode) */
63/* { */
64/* w = output->current_mode->width; */
65/* h = output->current_mode->height; */
66/* } */
67/* else */
68/* { */
69/* w = 1024; */
70/* h = 768; */
71/* } */
72
73/* flags = (GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); */
74
75/* if (!(output->surface = */
76/* gbm_surface_create(dev->gbm, w, h, GBM_FORMAT_ARGB8888, flags))) */
77/* { */
78/* ERR("Could not create output surface"); */
79/* return EINA_FALSE; */
80/* } */
81
82/* if (!(output->egl.surface = */
83/* eglCreateWindowSurface(dev->egl.disp, dev->egl.cfg, */
84/* output->surface, NULL))) */
85/* { */
86/* ERR("Could not create output egl surface"); */
87/* gbm_surface_destroy(output->surface); */
88/* return EINA_FALSE; */
89/* } */
90
91/* if (!dev->egl.ctxt) */
92/* { */
93/* if (!_ecore_drm_output_context_create(dev, output->egl.surface)) */
94/* { */
95/* ERR("Could not create context"); */
96/* gbm_surface_destroy(output->surface); */
97/* return EINA_FALSE; */
98/* } */
99/* } */
100
101/* flags = (GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE); */
102/* for (i = 0; i < NUM_FRAME_BUFFERS; i++) */
103/* { */
104/* if (output->cursor[i]) continue; */
105/* if (!(output->cursor[i] = */
106/* gbm_bo_create(dev->gbm, 64, 64, dev->format, flags))) */
107/* { */
108/* continue; */
109/* } */
110/* } */
111
112/* if ((!output->cursor[0]) || (!output->cursor[1])) */
113/* { */
114/* WRN("Hardware Cursor Buffers not available"); */
115/* dev->cursors_broken = EINA_TRUE; */
116/* } */
117
118/* return EINA_TRUE; */
119/* } */
120
121/* static void */
122/* _ecore_drm_output_hardware_render(Ecore_Drm_Output *output) */
123/* { */
124/* struct gbm_bo *bo; */
125/* int ret; */
126
127/* if (!output) return; */
128/* if (!output->current_mode) return; */
129
130/* glViewport(output->x, output->y, */
131/* output->current_mode->width, output->current_mode->height); */
132
133/* if (eglMakeCurrent(output->dev->egl.disp, output->egl.surface, */
134/* output->egl.surface, output->dev->egl.ctxt) == EGL_FALSE) */
135/* return; */
136
137/* glClearColor(1.0, 1.0, 0.0, 1.0); */
138/* glClear(GL_COLOR_BUFFER_BIT); */
139/* glFlush(); */
140
141/* eglSwapBuffers(output->dev->egl.disp, output->egl.surface); */
142
143/* if (!(bo = gbm_surface_lock_front_buffer(output->surface))) */
144/* { */
145/* ERR("Failed to lock front buffer"); */
146/* return; */
147/* } */
148
149/* if (!(output->next = _ecore_drm_fb_bo_get(output->dev, bo))) */
150/* { */
151/* ERR("Failed to get FB from bo"); */
152/* gbm_surface_release_buffer(output->surface, bo); */
153/* } */
154/* } */
155/* #endif */
156
157static Eina_Bool
158_ecore_drm_output_software_setup(Ecore_Drm_Device *dev, Ecore_Drm_Output *output)
159{
160 unsigned int i = 0;
161 int w = 0, h = 0;
162
163 if ((!dev) || (!output)) return EINA_FALSE;
164
165 if (output->current_mode)
166 {
167 w = output->current_mode->width;
168 h = output->current_mode->height;
169 }
170 else
171 {
172 w = 1024;
173 h = 768;
174 }
175
176 for (i = 0; i < NUM_FRAME_BUFFERS; i++)
177 {
178 if (!(output->dumb[i] = ecore_drm_fb_create(dev, w, h)))
179 {
180 ERR("Could not create dumb framebuffer %d", i);
181 goto err;
182 }
183 }
184
185 return EINA_TRUE;
186
187err:
188 for (i = 0; i < NUM_FRAME_BUFFERS; i++)
189 {
190 if (output->dumb[i]) ecore_drm_fb_destroy(output->dumb[i]);
191 output->dumb[i] = NULL;
192 }
193
194 return EINA_FALSE;
195}
196
197static void
198_ecore_drm_output_software_render(Ecore_Drm_Output *output)
199{
200 if (!output) return;
201 if (!output->current_mode) return;
202}
203
204static int
205_ecore_drm_output_crtc_find(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnector *conn)
206{
207 drmModeEncoder *enc;
208 unsigned int p;
209 int i = 0, j = 0;
210
211 for (j = 0; j < conn->count_encoders; j++)
212 {
213 /* get the encoder on this connector */
214 if (!(enc = drmModeGetEncoder(dev->drm.fd, conn->encoders[j])))
215 {
216 ERR("Failed to get encoder: %m");
217 return -1;
218 }
219
220 p = enc->possible_crtcs;
221 drmModeFreeEncoder(enc);
222
223 for (i = 0; i < res->count_crtcs; i++)
224 {
225 if ((p & (1 << i)) &&
226 (!(dev->crtc_allocator & (1 << res->crtcs[i]))))
227 {
228 return i;
229 }
230 }
231 }
232
233 return -1;
234}
235
236static Ecore_Drm_Output_Mode *
237_ecore_drm_output_mode_add(Ecore_Drm_Output *output, drmModeModeInfo *info)
238{
239 Ecore_Drm_Output_Mode *mode;
240 uint64_t refresh;
241
242 /* try to allocate space for mode */
243 if (!(mode = malloc(sizeof(Ecore_Drm_Output_Mode))))
244 {
245 ERR("Could not allocate space for mode");
246 return NULL;
247 }
248
249 mode->flags = 0;
250 mode->width = info->hdisplay;
251 mode->height = info->vdisplay;
252
253 refresh = (info->clock * 1000000LL / info->htotal + info->vtotal / 2) / info->vtotal;
254 if (info->flags & DRM_MODE_FLAG_INTERLACE)
255 refresh *= 2;
256 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
257 refresh /= 2;
258 if (info->vscan > 1)
259 refresh /= info->vscan;
260
261 mode->refresh = refresh;
262 mode->info = *info;
263
264 /* DBG("Added Mode: %dx%d@%d to Output %d", */
265 /* mode->width, mode->height, mode->refresh, output->crtc_id); */
266
267 output->modes = eina_list_append(output->modes, mode);
268
269 return mode;
270}
271
272static Ecore_Drm_Output *
273_ecore_drm_output_create(Ecore_Drm_Device *dev, drmModeRes *res, drmModeConnector *conn, int x, int y)
274{
275 Ecore_Drm_Output *output;
276 Ecore_Drm_Output_Mode *mode;
277 const char *conn_name;
278 char name[32];
279 int i = 0;
280 drmModeEncoder *enc;
281 drmModeModeInfo crtc_mode;
282 drmModeCrtc *crtc;
283 Eina_List *l;
284
285 i = _ecore_drm_output_crtc_find(dev, res, conn);
286 if (i < 0)
287 {
288 ERR("Could not find crtc or encoder for connector");
289 return NULL;
290 }
291
292 /* try to allocate space for output */
293 if (!(output = calloc(1, sizeof(Ecore_Drm_Output))))
294 {
295 ERR("Could not allocate space for output");
296 return NULL;
297 }
298
299 output->dev = dev;
300 output->x = x;
301 output->y = y;
302
303 output->subpixel = conn->subpixel;
304 output->make = eina_stringshare_add("unknown");
305 output->model = eina_stringshare_add("unknown");
306
307 if (conn->connector_type < ALEN(conn_types))
308 conn_name = conn_types[conn->connector_type];
309 else
310 conn_name = "UNKNOWN";
311
312 snprintf(name, sizeof(name), "%s%d", conn_name, conn->connector_type_id);
313 output->name = eina_stringshare_add(name);
314
315 output->crtc_id = res->crtcs[i];
316 dev->crtc_allocator |= (1 << output->crtc_id);
317 output->conn_id = conn->connector_id;
318 output->crtc = drmModeGetCrtc(dev->drm.fd, output->crtc_id);
319
320 memset(&mode, 0, sizeof(mode));
321 if ((enc = drmModeGetEncoder(dev->drm.fd, conn->encoder_id)))
322 {
323 crtc = drmModeGetCrtc(dev->drm.fd, enc->crtc_id);
324 drmModeFreeEncoder(enc);
325 if (!crtc) goto mode_err;
326 if (crtc->mode_valid) crtc_mode = crtc->mode;
327 drmModeFreeCrtc(crtc);
328 }
329
330 for (i = 0; i < conn->count_modes; i++)
331 {
332 if (!(mode = _ecore_drm_output_mode_add(output, &conn->modes[i])))
333 {
334 ERR("Failed to add mode to output");
335 goto mode_err;
336 }
337 }
338
339 EINA_LIST_REVERSE_FOREACH(output->modes, l, mode)
340 {
341 if (!memcmp(&crtc_mode, &mode->info, sizeof(crtc_mode)))
342 {
343 output->current_mode = mode;
344 break;
345 }
346 }
347
348 if (!output->current_mode)
349 output->current_mode = _ecore_drm_output_mode_add(output, &crtc_mode);
350
351/* #ifdef HAVE_GBM */
352/* if ((dev->use_hw_accel) && (dev->gbm)) */
353/* { */
354/* if (!_ecore_drm_output_hardware_setup(dev, output)) */
355/* { */
356/* ERR("Could not setup output for hardware acceleration"); */
357/* dev->use_hw_accel = EINA_FALSE; */
358/* if (!_ecore_drm_output_software_setup(dev, output)) */
359/* goto mode_err; */
360/* else */
361/* DBG("Setup Output %d for Software Rendering", output->crtc_id); */
362/* } */
363/* else */
364/* DBG("Setup Output %d for Hardware Acceleration", output->crtc_id); */
365/* } */
366/* else */
367/* #endif */
368 {
369 dev->use_hw_accel = EINA_FALSE;
370 if (!_ecore_drm_output_software_setup(dev, output))
371 goto mode_err;
372 else
373 DBG("Setup Output %d for Software Rendering", output->crtc_id);
374 }
375
376 /* TODO */
377
378 return output;
379
380mode_err:
381 EINA_LIST_FREE(output->modes, mode)
382 free(mode);
383 drmModeFreeCrtc(output->crtc);
384 dev->crtc_allocator &= ~(1 << output->crtc_id);
385 free(output);
386 return NULL;
387}
388
389void
390_ecore_drm_output_frame_finish(Ecore_Drm_Output *output)
391{
392 if (!output) return;
393
394 if (output->need_repaint) ecore_drm_output_repaint(output);
395
396 output->repaint_scheduled = EINA_FALSE;
397}
398
399void
400_ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb)
401{
402 if ((!output) || (!fb)) return;
403
404 if ((fb->mmap) && (fb != output->dumb[0]) && (fb != output->dumb[1]))
405 ecore_drm_fb_destroy(fb);
406/* #ifdef HAVE_GBM */
407/* else if (fb->bo) */
408/* gbm_bo_destroy(fb->bo); */
409/* #endif */
410}
411
412void
413_ecore_drm_output_repaint_start(Ecore_Drm_Output *output)
414{
415 unsigned int fb;
416
417 DBG("Output Repaint Start");
418
419 if (!output) return;
420
421 if (!output->current)
422 {
423 DBG("\tNo Current FB");
424 goto finish;
425 }
426
427 fb = output->current->id;
428
429 if (drmModePageFlip(output->dev->drm.fd, output->crtc_id, fb,
430 DRM_MODE_PAGE_FLIP_EVENT, output) < 0)
431 {
432 ERR("Could not schedule output page flip event");
433 goto finish;
434 }
435
436 return;
437
438finish:
439 _ecore_drm_output_frame_finish(output);
440}
441
442/**
443 * @defgroup Ecore_Drm_Output_Group
444 *
445 */
446
447/* TODO: DOXY !! */
448
449/* public functions */
450EAPI Eina_Bool
451ecore_drm_outputs_create(Ecore_Drm_Device *dev)
452{
453 Eina_Bool ret = EINA_TRUE;
454 Ecore_Drm_Output *output;
455 drmModeConnector *conn;
456 drmModeRes *res;
457 drmModeCrtc *crtc;
458 int i = 0, x = 0, y = 0;
459
460 /* DBG("Create outputs for %d", dev->drm.fd); */
461
462 /* get the resources */
463 if (!(res = drmModeGetResources(dev->drm.fd)))
464 {
465 ERR("Could not get resources for drm card: %m");
466 return EINA_FALSE;
467 }
468
469 if (!(dev->crtcs = calloc(res->count_crtcs, sizeof(unsigned int))))
470 {
471 ERR("Could not allocate space for crtcs");
472 /* free resources */
473 drmModeFreeResources(res);
474 return EINA_FALSE;
475 }
476
477 dev->crtc_count = res->count_crtcs;
478 memcpy(dev->crtcs, res->crtcs, sizeof(unsigned int) * res->count_crtcs);
479
480 dev->min_width = res->min_width;
481 dev->min_height = res->min_height;
482 dev->max_width = res->max_width;
483 dev->max_height = res->max_height;
484
485 for (i = 0; i < res->count_connectors; i++)
486 {
487 if (i > 0) break;
488 /* get the connector */
489 if (!(conn = drmModeGetConnector(dev->drm.fd, res->connectors[i])))
490 continue;
491
492 if ((conn->connection == DRM_MODE_CONNECTED) &&
493 (conn->count_modes > 0))
494 {
495 drmModeEncoder *enc;
496
497 /* create output for this connector */
498 if (!(output = _ecore_drm_output_create(dev, res, conn, x, y)))
499 {
500 /* free the connector */
501 drmModeFreeConnector(conn);
502 continue;
503 }
504
505 output->drm_fd = dev->drm.fd;
506 dev->outputs = eina_list_append(dev->outputs, output);
507
508 if (!(enc = drmModeGetEncoder(dev->drm.fd, conn->encoder_id)))
509 {
510 drmModeFreeConnector(conn);
511 continue;
512 }
513
514 if (!(crtc = drmModeGetCrtc(dev->drm.fd, enc->crtc_id)))
515 {
516 drmModeFreeEncoder(enc);
517 drmModeFreeConnector(conn);
518 continue;
519 }
520
521 x += crtc->width;
522
523 drmModeFreeCrtc(crtc);
524 drmModeFreeEncoder(enc);
525 }
526
527 /* free the connector */
528 drmModeFreeConnector(conn);
529 }
530
531 ret = EINA_TRUE;
532 if (eina_list_count(dev->outputs) < 1)
533 {
534 ret = EINA_FALSE;
535 free(dev->crtcs);
536 }
537
538 /* free resources */
539 drmModeFreeResources(res);
540
541 /* TODO: add hook for udev drm output updates */
542
543 return ret;
544}
545
546EAPI void
547ecore_drm_output_free(Ecore_Drm_Output *output)
548{
549 Ecore_Drm_Output_Mode *mode;
550
551 /* check for valid output */
552 if (!output) return;
553
554 /* free modes */
555 EINA_LIST_FREE(output->modes, mode)
556 free(mode);
557
558 /* free strings */
559 if (output->name) eina_stringshare_del(output->name);
560 if (output->model) eina_stringshare_del(output->model);
561 if (output->make) eina_stringshare_del(output->make);
562
563 free(output);
564}
565
566EAPI void
567ecore_drm_output_cursor_size_set(Ecore_Drm_Output *output, int handle, int w, int h)
568{
569 if (!output) return;
570 drmModeSetCursor(output->drm_fd, output->crtc_id, handle, w, h);
571}
572
573EAPI Eina_Bool
574ecore_drm_output_enable(Ecore_Drm_Output *output)
575{
576 Ecore_Drm_Output_Mode *mode;
577
578 if ((!output) || (!output->current)) return EINA_FALSE;
579
580 mode = output->current_mode;
581 if (drmModeSetCrtc(output->drm_fd, output->crtc_id, output->current->id,
582 0, 0, &output->conn_id, 1, &mode->info) < 0)
583 {
584 ERR("Could not set output crtc: %m");
585 return EINA_FALSE;
586 }
587
588 return EINA_TRUE;
589}
590
591EAPI void
592ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb)
593{
594 if ((!output) || (!fb)) return;
595
596 if ((fb->mmap) && (fb != output->dumb[0]) && (fb != output->dumb[1]))
597 ecore_drm_fb_destroy(fb);
598/* #ifdef HAVE_GBM */
599/* else if (fb->bo) */
600/* { */
601/* if (fb->from_client) */
602/* gbm_bo_destroy(fb->bo); */
603/* else */
604/* gbm_surface_release_buffer(output->surface, fb->bo); */
605/* } */
606/* #endif */
607}
608
609EAPI void
610ecore_drm_output_repaint(Ecore_Drm_Output *output)
611{
612 Eina_List *l;
613 Ecore_Drm_Sprite *sprite;
614 int ret = 0;
615
616 if (!output) return;
617
618 DBG("Output Repaint: %d %d", output->crtc_id, output->conn_id);
619
620 /* TODO: assign planes ? */
621
622 if (!output->next)
623 {
624/* #ifdef HAVE_GBM */
625/* if (output->dev->use_hw_accel) */
626/* { */
627/* _ecore_drm_output_hardware_render(output); */
628/* } */
629/* else */
630/* #endif */
631 {
632 _ecore_drm_output_software_render(output);
633 }
634 }
635
636 if (!output->next)
637 {
638 DBG("\tNo Next Fb");
639 return;
640 }
641
642 output->need_repaint = EINA_FALSE;
643
644 if (!output->current)
645 {
646 Ecore_Drm_Output_Mode *mode;
647
648 mode = output->current_mode;
649
650 ret = drmModeSetCrtc(output->dev->drm.fd, output->crtc_id,
651 output->next->id, 0, 0, &output->conn_id, 1,
652 &mode->info);
653 if (ret)
654 {
655 ERR("Setting output mode failed");
656 goto err;
657 }
658 }
659
660 if (drmModePageFlip(output->dev->drm.fd, output->crtc_id, output->next->id,
661 DRM_MODE_PAGE_FLIP_EVENT, output) < 0)
662 {
663 ERR("Scheduling pageflip failed");
664 goto err;
665 }
666
667 output->pending_flip = EINA_TRUE;
668
669 EINA_LIST_FOREACH(output->dev->sprites, l, sprite)
670 {
671 unsigned int flags = 0, id = 0;
672 drmVBlank vbl =
673 {
674 .request.type = (DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT),
675 .request.sequence = 1,
676 };
677
678 if (((!sprite->current_fb) && (!sprite->next_fb)) ||
679 (!ecore_drm_sprites_crtc_supported(output, sprite->crtcs)))
680 continue;
681
682 if ((sprite->next_fb) && (!output->dev->cursors_broken))
683 id = sprite->next_fb->id;
684
685 ecore_drm_sprites_fb_set(sprite, id, flags);
686
687 vbl.request.signal = (unsigned long)sprite;
688 ret = drmWaitVBlank(output->dev->drm.fd, &vbl);
689 if (ret) ERR("Error Wait VBlank: %m");
690
691 sprite->output = output;
692 output->pending_vblank = EINA_TRUE;
693 }
694
695 return;
696
697err:
698 if (output->next)
699 {
700 ecore_drm_output_fb_release(output, output->next);
701 output->next = NULL;
702 }
703}
diff --git a/src/lib/ecore_drm/ecore_drm_private.h b/src/lib/ecore_drm/ecore_drm_private.h
new file mode 100644
index 0000000000..51cd78283b
--- /dev/null
+++ b/src/lib/ecore_drm/ecore_drm_private.h
@@ -0,0 +1,281 @@
1#ifndef _ECORE_DRM_PRIVATE_H
2# define _ECORE_DRM_PRIVATE_H
3
4# include "Ecore.h"
5# include "ecore_private.h"
6# include "Ecore_Input.h"
7
8# include <stdio.h>
9# include <stdlib.h>
10# include <string.h>
11# include <unistd.h>
12# include <errno.h>
13# include <sys/mman.h>
14# include <fcntl.h>
15
16# include <libudev.h>
17# include <linux/input.h>
18//# include <libinput.h>
19
20# include <xf86drm.h>
21# include <xf86drmMode.h>
22# include <drm_fourcc.h>
23
24/* # ifdef HAVE_GBM */
25/* # include <gbm.h> */
26/* # include <EGL/egl.h> */
27/* # include <EGL/eglext.h> */
28/* # include <GLES2/gl2.h> */
29/* # include <GLES2/gl2ext.h> */
30/* # endif */
31
32# include <Ecore_Drm.h>
33
34# ifndef DRM_MAJOR
35# define DRM_MAJOR 226
36# endif
37
38# ifndef DRM_CAP_TIMESTAMP_MONOTONIC
39# define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
40# endif
41
42# ifdef ECORE_DRM_DEFAULT_LOG_COLOR
43# undef ECORE_DRM_DEFAULT_LOG_COLOR
44# endif
45# define ECORE_DRM_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
46
47# define EVDEV_SEAT_POINTER (1 << 0)
48# define EVDEV_SEAT_KEYBOARD (1 << 1)
49# define EVDEV_SEAT_TOUCH (1 << 2)
50
51# ifdef ERR
52# undef ERR
53# endif
54# ifdef DBG
55# undef DBG
56# endif
57# ifdef INF
58# undef INF
59# endif
60# ifdef WRN
61# undef WRN
62# endif
63# ifdef CRIT
64# undef CRIT
65# endif
66
67extern int _ecore_drm_log_dom;
68
69/* undef this for non-testing builds */
70# define LOG_TO_FILE
71
72# ifdef LOG_TO_FILE
73extern FILE *lg;
74
75# define ERR(...) \
76 EINA_LOG_DOM_ERR(_ecore_drm_log_dom, __VA_ARGS__); \
77 fflush(lg);
78
79# define DBG(...) \
80 EINA_LOG_DOM_DBG(_ecore_drm_log_dom, __VA_ARGS__); \
81 fflush(lg);
82
83# define INF(...) \
84 EINA_LOG_DOM_INFO(_ecore_drm_log_dom, __VA_ARGS__); \
85 fflush(lg);
86
87# define WRN(...) \
88 EINA_LOG_DOM_WARN(_ecore_drm_log_dom, __VA_ARGS__); \
89 fflush(lg);
90
91# define CRIT(...) \
92 EINA_LOG_DOM_CRIT(_ecore_drm_log_dom, __VA_ARGS__); \
93 fflush(lg);
94
95# else
96# define ERR(...) EINA_LOG_DOM_ERR(_ecore_drm_log_dom, __VA_ARGS__)
97# define DBG(...) EINA_LOG_DOM_DBG(_ecore_drm_log_dom, __VA_ARGS__)
98# define INF(...) EINA_LOG_DOM_INFO(_ecore_drm_log_dom, __VA_ARGS__)
99# define WRN(...) EINA_LOG_DOM_WARN(_ecore_drm_log_dom, __VA_ARGS__)
100# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_drm_log_dom, __VA_ARGS__)
101# endif
102
103extern struct udev *udev;
104
105struct _Ecore_Drm_Output_Mode
106{
107 unsigned int flags;
108 int width, height;
109 unsigned int refresh;
110 drmModeModeInfo info;
111};
112
113struct _Ecore_Drm_Output
114{
115 Ecore_Drm_Device *dev;
116 unsigned int crtc_id;
117 unsigned int conn_id;
118 drmModeCrtcPtr crtc;
119
120 int x, y;
121 int drm_fd;
122
123 Eina_Bool need_repaint : 1;
124 Eina_Bool repaint_scheduled : 1;
125
126 Eina_Bool pending_flip : 1;
127 Eina_Bool pending_vblank : 1;
128
129 const char *make, *model, *name;
130 unsigned int subpixel;
131
132 Ecore_Drm_Output_Mode *current_mode;
133 Eina_List *modes;
134
135 Ecore_Drm_Fb *current, *next;
136 Ecore_Drm_Fb *dumb[NUM_FRAME_BUFFERS];
137
138/* # ifdef HAVE_GBM */
139/* struct gbm_surface *surface; */
140/* struct gbm_bo *cursor[NUM_FRAME_BUFFERS]; */
141/* struct */
142/* { */
143/* EGLSurface surface; */
144/* } egl; */
145/* # endif */
146
147 /* TODO: finish */
148};
149
150struct _Ecore_Drm_Seat
151{
152// struct libinput_seat *seat;
153 const char *name;
154 Ecore_Drm_Input *input;
155 Eina_List *devices;
156};
157
158struct _Ecore_Drm_Input
159{
160 int fd;
161 const char *seat;
162 struct udev_monitor *monitor;
163 Ecore_Fd_Handler *hdlr;
164 Ecore_Drm_Device *dev;
165
166 Eina_Bool enabled : 1;
167 Eina_Bool suspended : 1;
168};
169
170struct _Ecore_Drm_Evdev
171{
172 Ecore_Drm_Seat *seat;
173 /* struct libinput *linput; */
174 /* struct libinput_device *dev; */
175 const char *name, *path;
176 int fd;
177
178 struct
179 {
180 int min_x, min_y;
181 int max_x, max_y;
182 int x, y;
183 } abs;
184
185 Ecore_Drm_Evdev_Event_Type pending_event;
186 Ecore_Drm_Evdev_Capabilities caps;
187 Ecore_Drm_Seat_Capabilities seat_caps;
188
189 void (*event_process)(Ecore_Drm_Evdev *dev, struct input_event *event, int count);
190
191 Ecore_Fd_Handler *hdlr;
192};
193
194struct _Ecore_Drm_Sprite
195{
196 Ecore_Drm_Fb *current_fb, *next_fb;
197 Ecore_Drm_Output *output;
198
199 int drm_fd;
200
201 unsigned int crtcs;
202 unsigned int plane_id;
203
204 struct
205 {
206 int x, y;
207 unsigned int w, h;
208 } src, dest;
209
210 unsigned int num_formats;
211 unsigned int formats[];
212};
213
214struct _Ecore_Drm_Device
215{
216 int id;
217 const char *seat;
218
219 struct
220 {
221 int fd;
222 const char *name;
223 const char *path;
224 clockid_t clock;
225 Ecore_Fd_Handler *hdlr;
226 Ecore_Idle_Enterer *idler;
227 } drm;
228
229 unsigned int min_width, min_height;
230 unsigned int max_width, max_height;
231
232 unsigned int crtc_count;
233 unsigned int *crtcs;
234 unsigned int crtc_allocator;
235
236 Eina_List *seats;
237 Eina_List *inputs;
238 Eina_List *outputs;
239 Eina_List *sprites;
240
241 struct
242 {
243 int fd;
244 const char *name;
245 Ecore_Event_Handler *event_hdlr;
246 } tty;
247
248 unsigned int format;
249 Eina_Bool use_hw_accel : 1;
250 Eina_Bool cursors_broken : 1;
251
252/* #ifdef HAVE_GBM */
253/* struct gbm_device *gbm; */
254/* struct */
255/* { */
256/* EGLDisplay disp; */
257/* EGLContext ctxt; */
258/* EGLConfig cfg; */
259/* } egl; */
260/* #endif */
261};
262
263void _ecore_drm_message_send(int opcode, int fd, void *data, size_t bytes);
264Eina_Bool _ecore_drm_message_receive(int opcode, int *fd, void **data, size_t bytes);
265
266Ecore_Drm_Evdev *_ecore_drm_evdev_device_create(Ecore_Drm_Seat *seat, const char *path, int fd);
267void _ecore_drm_evdev_device_destroy(Ecore_Drm_Evdev *evdev);
268/* int _ecore_drm_evdev_event_process(struct libinput_event *event); */
269
270Ecore_Drm_Fb *_ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height);
271void _ecore_drm_fb_destroy(Ecore_Drm_Fb *fb);
272
273/* #ifdef HAVE_GBM */
274/* Ecore_Drm_Fb *_ecore_drm_fb_bo_get(Ecore_Drm_Device *dev, struct gbm_bo *bo); */
275/* #endif */
276
277void _ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb);
278void _ecore_drm_output_repaint_start(Ecore_Drm_Output *output);
279void _ecore_drm_output_frame_finish(Ecore_Drm_Output *output);
280
281#endif
diff --git a/src/lib/ecore_drm/ecore_drm_sprites.c b/src/lib/ecore_drm/ecore_drm_sprites.c
new file mode 100644
index 0000000000..b457afe018
--- /dev/null
+++ b/src/lib/ecore_drm/ecore_drm_sprites.c
@@ -0,0 +1,115 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "ecore_drm_private.h"
6
7/**
8 * @defgroup Ecore_Drm_Fb_Group
9 *
10 */
11
12/* TODO: DOXY !! */
13
14EAPI Eina_Bool
15ecore_drm_sprites_create(Ecore_Drm_Device *dev)
16{
17 drmModePlaneRes *res;
18 drmModePlane *p;
19 unsigned int i = 0;
20
21 /* check for valid device */
22 if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
23
24 /* get plane resources */
25 if (!(res = drmModeGetPlaneResources(dev->drm.fd))) return EINA_FALSE;
26
27 for (i = 0; i < res->count_planes; i++)
28 {
29 Ecore_Drm_Sprite *sprite;
30
31 if (!(p = drmModeGetPlane(dev->drm.fd, res->planes[i])))
32 continue;
33
34 /* allocate space for sprite */
35 if (!(sprite =
36 malloc(sizeof(Ecore_Drm_Sprite) +
37 ((sizeof(unsigned int)) * p->count_formats))))
38 {
39 drmModeFreePlane(p);
40 continue;
41 }
42
43 sprite->drm_fd = dev->drm.fd;
44 sprite->crtcs = p->possible_crtcs;
45 sprite->plane_id = p->plane_id;
46 sprite->num_formats = p->count_formats;
47 memcpy(sprite->formats, p->formats,
48 p->count_formats * sizeof(p->formats[0]));
49 drmModeFreePlane(p);
50
51 dev->sprites = eina_list_append(dev->sprites, sprite);
52 }
53
54 /* free resources */
55 drmModeFreePlaneResources(res);
56
57 return EINA_TRUE;
58}
59
60EAPI void
61ecore_drm_sprites_destroy(Ecore_Drm_Device *dev)
62{
63 Ecore_Drm_Sprite *sprite;
64
65 /* check for valid device */
66 if (!dev) return;
67
68 EINA_LIST_FREE(dev->sprites, sprite)
69 {
70 ecore_drm_sprites_fb_set(sprite, 0, 0);
71
72 _ecore_drm_output_fb_release(sprite->output, sprite->current_fb);
73 _ecore_drm_output_fb_release(sprite->output, sprite->next_fb);
74
75 free(sprite);
76 }
77}
78
79EAPI void
80ecore_drm_sprites_fb_set(Ecore_Drm_Sprite *sprite, int fb_id, int flags)
81{
82 if ((!sprite) || (!sprite->output)) return;
83
84 if (fb_id)
85 {
86 drmModeSetPlane(sprite->drm_fd, sprite->plane_id,
87 sprite->output->crtc_id, fb_id, flags,
88 sprite->dest.x, sprite->dest.y, sprite->dest.w,
89 sprite->dest.h, sprite->src.x, sprite->src.y,
90 sprite->src.w, sprite->src.h);
91 }
92 else
93 {
94 drmModeSetPlane(sprite->drm_fd, sprite->plane_id,
95 sprite->output->crtc_id, 0, 0,
96 0, 0, 0, 0, 0, 0, 0, 0);
97 }
98}
99
100EAPI Eina_Bool
101ecore_drm_sprites_crtc_supported(Ecore_Drm_Output *output, unsigned int supported)
102{
103 Ecore_Drm_Device *dev;
104 unsigned int c = 0;
105
106 dev = output->dev;
107
108 for (c = 0; c < dev->crtc_count; c++)
109 {
110 if (dev->crtcs[c] != output->crtc_id) continue;
111 if ((supported) && (1 << c)) return EINA_FALSE;
112 }
113
114 return EINA_TRUE;
115}
diff --git a/src/lib/ecore_drm/ecore_drm_tty.c b/src/lib/ecore_drm/ecore_drm_tty.c
new file mode 100644
index 0000000000..41a0561fb7
--- /dev/null
+++ b/src/lib/ecore_drm/ecore_drm_tty.c
@@ -0,0 +1,297 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include "ecore_drm_private.h"
6#include <sys/stat.h>
7#include <sys/ioctl.h>
8#include <linux/vt.h>
9#include <linux/kd.h>
10
11#ifndef KDSKBMUTE
12# define KDSKBMUTE 0x4B51
13#endif
14
15static Eina_Bool
16_ecore_drm_tty_cb_signal(void *data, int type EINA_UNUSED, void *event)
17{
18 Ecore_Drm_Device *dev;
19 Ecore_Event_Signal_User *ev;
20
21 dev = data;
22 ev = event;
23
24 DBG("Caught user signal: %d", ev->number);
25
26 if (ev->number == 1)
27 {
28 Ecore_Drm_Input *input;
29 Ecore_Drm_Output *output;
30 Ecore_Drm_Sprite *sprite;
31 Eina_List *l;
32
33 DBG("Release VT");
34
35 /* disable inputs (suspends) */
36 EINA_LIST_FOREACH(dev->inputs, l, input)
37 ecore_drm_inputs_disable(input);
38
39 /* disable hardware cursor */
40 EINA_LIST_FOREACH(dev->outputs, l, output)
41 ecore_drm_output_cursor_size_set(output, 0, 0, 0);
42
43 /* disable sprites */
44 EINA_LIST_FOREACH(dev->sprites, l, sprite)
45 ecore_drm_sprites_fb_set(sprite, 0, 0);
46
47 /* close input fds ?? */
48
49 /* drop drm master */
50 if (ecore_drm_device_master_drop(dev))
51 {
52 /* issue ioctl to release vt */
53 if (!ecore_drm_tty_release(dev))
54 ERR("Could not release VT: %m");
55 }
56 else
57 ERR("Could not drop drm master: %m");
58 }
59 else if (ev->number == 2)
60 {
61 Ecore_Drm_Output *output;
62 Ecore_Drm_Input *input;
63 Eina_List *l;
64
65 DBG("Acquire VT");
66
67 /* issue ioctl to acquire vt */
68 if (ecore_drm_tty_acquire(dev))
69 {
70 /* set drm master */
71 if (!ecore_drm_device_master_set(dev))
72 ERR("Could not set drm master: %m");
73
74 /* set output mode */
75 EINA_LIST_FOREACH(dev->outputs, l, output)
76 ecore_drm_output_enable(output);
77
78 /* enable inputs */
79 EINA_LIST_FOREACH(dev->inputs, l, input)
80 ecore_drm_inputs_enable(input);
81 }
82 else
83 ERR("Could not acquire VT: %m");
84 }
85
86 return EINA_TRUE;
87}
88
89static Eina_Bool
90_ecore_drm_tty_setup(Ecore_Drm_Device *dev)
91{
92 struct stat st;
93 int kb_mode;
94 struct vt_mode vtmode = { 0 };
95
96 if (fstat(dev->tty.fd, &st) == -1)
97 {
98 ERR("Failed to get stats for tty: %m");
99 return EINA_FALSE;
100 }
101
102 if (ioctl(dev->tty.fd, KDGKBMODE, &kb_mode))
103 {
104 ERR("Could not get tty keyboard mode: %m");
105 return EINA_FALSE;
106 }
107
108 /* NB: Don't set this. This Turns OFF keyboard on the VT */
109 /* if (ioctl(dev->tty.fd, KDSKBMUTE, 1) && */
110 /* ioctl(dev->tty.fd, KDSKBMODE, K_OFF)) */
111 /* { */
112 /* ERR("Could not set K_OFF keyboard mode: %m"); */
113 /* return EINA_FALSE; */
114 /* } */
115
116 /* if (ioctl(dev->tty.fd, KDSETMODE, KD_GRAPHICS)) */
117 /* { */
118 /* ERR("Could not set graphics mode: %m"); */
119 /* return EINA_FALSE; */
120 /* } */
121
122 vtmode.mode = VT_PROCESS;
123 vtmode.waitv = 0;
124 vtmode.relsig = SIGUSR1;
125 vtmode.acqsig = SIGUSR2;
126 if (ioctl(dev->tty.fd, VT_SETMODE, &vtmode) < 0)
127 {
128 ERR("Could not set Terminal Mode: %m");
129 return EINA_FALSE;
130 }
131
132 /* if (ioctl(dev->tty.fd, VT_ACTIVATE, minor(st.st_rdev)) < 0) */
133 /* { */
134 /* ERR("Failed to activate vt: %m"); */
135 /* return EINA_FALSE; */
136 /* } */
137
138 /* if (ioctl(dev->tty.fd, VT_WAITACTIVE, minor(st.st_rdev)) < 0) */
139 /* { */
140 /* ERR("Failed to wait active: %m"); */
141 /* return EINA_FALSE; */
142 /* } */
143
144 return EINA_TRUE;
145}
146
147/**
148 * @defgroup Ecore_Drm_Tty_Group Tty manipulation functions
149 *
150 * Functions that deal with opening, closing, and otherwise using a tty
151 */
152
153/**
154 * Open a tty for use
155 *
156 * @param dev The Ecore_Drm_Device that this tty will belong to.
157 * @param name The name of the tty to try and open.
158 * If NULL, /dev/tty0 will be used.
159 *
160 * @return EINA_TRUE on success, EINA_FALSE on failure
161 *
162 * @ingroup Ecore_Drm_Tty_Group
163 */
164EAPI Eina_Bool
165ecore_drm_tty_open(Ecore_Drm_Device *dev, const char *name)
166{
167 char tty[32] = "<stdin>";
168
169 /* check for valid device */
170 if ((!dev) || (!dev->drm.name)) return EINA_FALSE;
171
172 /* assign default tty fd of -1 */
173 dev->tty.fd = -1;
174
175 if (!name)
176 {
177 char *env;
178
179 if ((env = getenv("ECORE_DRM_TTY")))
180 snprintf(tty, sizeof(tty), "%s", env);
181 else
182 dev->tty.fd = STDIN_FILENO;
183 }
184 else // FIXME: NB: This should Really check for format of name (/dev/xyz)
185 snprintf(tty, sizeof(tty), "%s", name);
186
187 if (dev->tty.fd < 0)
188 {
189 DBG("Trying to Open Tty: %s", tty);
190
191 dev->tty.fd = open(tty, O_RDWR | O_NOCTTY);
192 if (dev->tty.fd < 0)
193 {
194 DBG("Failed to Open Tty: %m");
195 return EINA_FALSE;
196 }
197 }
198
199 if (dev->tty.fd < 0)
200 {
201 DBG("Failed to open tty %s", tty);
202 return EINA_FALSE;
203 }
204
205 DBG("Opened Tty %s : %d", tty, dev->tty.fd);
206
207 /* save tty name */
208 dev->tty.name = eina_stringshare_add(tty);
209
210 /* FIXME */
211 if (!_ecore_drm_tty_setup(dev))
212 return EINA_FALSE;
213
214 /* setup handler for signals */
215 dev->tty.event_hdlr =
216 ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER,
217 _ecore_drm_tty_cb_signal, dev);
218
219 /* set current tty into env */
220 setenv("ECORE_DRM_TTY", tty, 1);
221
222 return EINA_TRUE;
223}
224
225/**
226 * Close an already opened tty
227 *
228 * @param dev The Ecore_Drm_Device which owns this tty.
229 *
230 * @return EINA_TRUE on success, EINA_FALSE on failure
231 *
232 * @ingroup Ecore_Drm_Tty_Group
233 */
234EAPI Eina_Bool
235ecore_drm_tty_close(Ecore_Drm_Device *dev)
236{
237 /* check for valid device */
238 if ((!dev) || (!dev->drm.name)) return EINA_FALSE;
239
240 close(dev->tty.fd);
241
242 dev->tty.fd = -1;
243
244 /* destroy the event handler */
245 if (dev->tty.event_hdlr) ecore_event_handler_del(dev->tty.event_hdlr);
246 dev->tty.event_hdlr = NULL;
247
248 /* clear the tty name */
249 if (dev->tty.name) eina_stringshare_del(dev->tty.name);
250 dev->tty.name = NULL;
251
252 unsetenv("ECORE_DRM_TTY");
253
254 return EINA_TRUE;
255}
256
257/**
258 * Release a virtual terminal
259 *
260 * @param dev The Ecore_Drm_Device which owns this tty.
261 *
262 * @return EINA_TRUE on success, EINA_FALSE on failure
263 *
264 * @ingroup Ecore_Drm_Tty_Group
265 */
266EAPI Eina_Bool
267ecore_drm_tty_release(Ecore_Drm_Device *dev)
268{
269 /* check for valid device */
270 if ((!dev) || (!dev->drm.name) || (dev->tty.fd < 0)) return EINA_FALSE;
271
272 /* send ioctl for vt release */
273 if (ioctl(dev->tty.fd, VT_RELDISP, 1) < 0) return EINA_FALSE;
274
275 return EINA_TRUE;
276}
277
278/**
279 * Acquire a virtual terminal
280 *
281 * @param dev The Ecore_Drm_Device which owns this tty.
282 *
283 * @return EINA_TRUE on success, EINA_FALSE on failure
284 *
285 * @ingroup Ecore_Drm_Tty_Group
286 */
287EAPI Eina_Bool
288ecore_drm_tty_acquire(Ecore_Drm_Device *dev)
289{
290 /* check for valid device */
291 if ((!dev) || (!dev->drm.name) || (dev->tty.fd < 0)) return EINA_FALSE;
292
293 /* send ioctl for vt acquire */
294 if (ioctl(dev->tty.fd, VT_RELDISP, VT_ACKACQ) < 0) return EINA_FALSE;
295
296 return EINA_TRUE;
297}