summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--configure.ac43
-rw-r--r--pc/ecore-drm.pc.in12
-rw-r--r--src/Makefile.am1
-rw-r--r--src/Makefile_Ecore_Drm.am56
-rw-r--r--src/bin/ecore_drm/ecore_drm_launch.c407
-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.c584
-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.h283
-rw-r--r--src/lib/ecore_drm/ecore_drm_sprites.c115
-rw-r--r--src/lib/ecore_drm/ecore_drm_tty.c297
-rw-r--r--src/modules/evas/engines/drm/Evas_Engine_Drm.h15
-rw-r--r--src/modules/evas/engines/drm/evas_bufmgr.c10
17 files changed, 3909 insertions, 16 deletions
diff --git a/configure.ac b/configure.ac
index 75d7297508..16d9eee296 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2570,6 +2570,44 @@ EFL_EVAL_PKGS([ECORE_WAYLAND])
2570EFL_LIB_END_OPTIONAL([Ecore_Wayland]) 2570EFL_LIB_END_OPTIONAL([Ecore_Wayland])
2571#### End of Ecore_Wayland 2571#### End of Ecore_Wayland
2572 2572
2573#### Ecore_Drm
2574EFL_LIB_START_OPTIONAL([Ecore_Drm], [test "${want_drm}" = "yes"])
2575
2576### Additional options to configure
2577SUID_CFLAGS=-fPIE
2578SUID_LDFLAGS=-pie
2579AC_SUBST([SUID_CFLAGS])
2580AC_SUBST([SUID_LDFLAGS])
2581
2582### Default values
2583
2584### Checks for programs
2585
2586### Checks for libraries
2587EFL_INTERNAL_DEPEND_PKG([ECORE_DRM], [ecore])
2588EFL_INTERNAL_DEPEND_PKG([ECORE_DRM], [ecore-input])
2589EFL_INTERNAL_DEPEND_PKG([ECORE_DRM], [eo])
2590EFL_INTERNAL_DEPEND_PKG([ECORE_DRM], [eina])
2591
2592EFL_DEPEND_PKG([ECORE_DRM], [DRM], [libudev >= 148 libdrm >= 2.4])
2593
2594EFL_EVAL_PKGS([ECORE_DRM])
2595
2596### Checks for header files
2597
2598### Checks for types
2599
2600### Checks for structures
2601
2602### Checks for compiler characteristics
2603
2604### Checks for linker characteristics
2605
2606### Checks for library functions
2607
2608EFL_LIB_END_OPTIONAL([Ecore_Drm])
2609#### End of Ecore_Drm
2610
2573 2611
2574#### Ecore_Audio 2612#### Ecore_Audio
2575 2613
@@ -3399,7 +3437,9 @@ AM_CONDITIONAL([BUILD_ECORE_EVAS_SDL],
3399 3437
3400ECORE_EVAS_MODULE([wayland-shm], [${want_wayland}]) 3438ECORE_EVAS_MODULE([wayland-shm], [${want_wayland}])
3401ECORE_EVAS_MODULE([wayland-egl], [${want_ecore_evas_wayland_egl}]) 3439ECORE_EVAS_MODULE([wayland-egl], [${want_ecore_evas_wayland_egl}])
3402ECORE_EVAS_MODULE([drm], [${want_drm}]) 3440ECORE_EVAS_MODULE([drm], [${want_drm}],
3441 [ EFL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [ecore-drm]) ]
3442)
3403 3443
3404build_ecore_evas_wayland="no" 3444build_ecore_evas_wayland="no"
3405if test "x${have_ecore_evas_wayland_shm}" = "xyes" || \ 3445if test "x${have_ecore_evas_wayland_shm}" = "xyes" || \
@@ -4037,6 +4077,7 @@ pc/ecore-file.pc
4037pc/ecore-input.pc 4077pc/ecore-input.pc
4038pc/ecore-input-evas.pc 4078pc/ecore-input-evas.pc
4039pc/ecore-cocoa.pc 4079pc/ecore-cocoa.pc
4080pc/ecore-drm.pc
4040pc/ecore-fb.pc 4081pc/ecore-fb.pc
4041pc/ecore-psl1ght.pc 4082pc/ecore-psl1ght.pc
4042pc/ecore-sdl.pc 4083pc/ecore-sdl.pc
diff --git a/pc/ecore-drm.pc.in b/pc/ecore-drm.pc.in
new file mode 100644
index 0000000000..8b243e8920
--- /dev/null
+++ b/pc/ecore-drm.pc.in
@@ -0,0 +1,12 @@
1prefix=@prefix@
2exec_prefix=@exec_prefix@
3libdir=@libdir@
4includedir=@includedir@
5
6Name: ecore-drm
7Description: E core library, DRM module
8Requires.private: @requirements_pc_ecore_drm@
9Version: @VERSION@
10Libs: -L${libdir} -lecore_drm
11Libs.private: @requirements_libs_ecore_drm@
12Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/ecore-drm-@VMAJ@
diff --git a/src/Makefile.am b/src/Makefile.am
index 20b5384712..e70de8cfe2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,6 +35,7 @@ include Makefile_Ecore_File.am
35include Makefile_Ecore_Input.am 35include Makefile_Ecore_Input.am
36include Makefile_Ecore_Input_Evas.am 36include Makefile_Ecore_Input_Evas.am
37include Makefile_Ecore_Cocoa.am 37include Makefile_Ecore_Cocoa.am
38include Makefile_Ecore_Drm.am
38include Makefile_Ecore_FB.am 39include Makefile_Ecore_FB.am
39include Makefile_Ecore_Psl1ght.am 40include Makefile_Ecore_Psl1ght.am
40include Makefile_Ecore_SDL.am 41include Makefile_Ecore_SDL.am
diff --git a/src/Makefile_Ecore_Drm.am b/src/Makefile_Ecore_Drm.am
new file mode 100644
index 0000000000..42b280cf31
--- /dev/null
+++ b/src/Makefile_Ecore_Drm.am
@@ -0,0 +1,56 @@
1if HAVE_ECORE_DRM
2
3### Library
4
5lib_LTLIBRARIES += lib/ecore_drm/libecore_drm.la
6
7installed_ecoredrmmainheadersdir = $(includedir)/ecore-drm-@VMAJ@
8dist_installed_ecoredrmmainheaders_DATA = \
9 lib/ecore_drm/Ecore_Drm.h
10
11lib_ecore_drm_libecore_drm_la_SOURCES = \
12lib/ecore_drm/ecore_drm_sprites.c \
13lib/ecore_drm/ecore_drm_fb.c \
14lib/ecore_drm/ecore_drm_evdev.c \
15lib/ecore_drm/ecore_drm_inputs.c \
16lib/ecore_drm/ecore_drm_output.c \
17lib/ecore_drm/ecore_drm_tty.c \
18lib/ecore_drm/ecore_drm_device.c \
19lib/ecore_drm/ecore_drm.c \
20lib/ecore_drm/ecore_drm_private.h
21
22lib_ecore_drm_libecore_drm_la_CPPFLAGS = \
23 -I$(top_builddir)/src/lib/efl \
24 @ECORE_DRM_CFLAGS@ \
25 -DPACKAGE_LIB_DIR=\"$(libdir)\" \
26 -DMODULE_ARCH=\"$(MODULE_ARCH)\"
27
28lib_ecore_drm_libecore_drm_la_LIBADD = @ECORE_DRM_LIBS@
29lib_ecore_drm_libecore_drm_la_DEPENDENCIES = @ECORE_DRM_INTERNAL_LIBS@
30lib_ecore_drm_libecore_drm_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
31
32### Drm Launch Binary
33
34ecoredrmlaunchinternal_bindir = $(libdir)/ecore_drm/bin/$(MODULE_ARCH)
35ecoredrmlaunchinternal_bin_PROGRAMS = bin/ecore_drm/ecore_drm_launch
36
37bin_ecore_drm_ecore_drm_launch_SOURCES = \
38 bin/ecore_drm/ecore_drm_launch.c
39
40bin_ecore_drm_ecore_drm_launch_CPPFLAGS = \
41 -I$(top_builddir)/src/lib/efl \
42 @ECORE_DRM_CFLAGS@ @SUID_CFLAGS@ \
43 -DPACKAGE_LIB_DIR=\"$(libdir)\" \
44 -DMODULE_ARCH=\"$(MODULE_ARCH)\"
45
46bin_ecore_drm_ecore_drm_launch_LDADD = \
47 @ECORE_DRM_LIBS@ \
48 @SUID_LDFLAGS@
49
50bin_ecore_drm_ecore_drm_launch_DEPENDENCIES = \
51 @USE_ECORE_DRM_INTERNAL_LIBS@
52
53setuid_root_mode = a=rx,u+xs
54EFL_INSTALL_EXEC_HOOK += @chmod $(setuid_root_mode) $(DESTDIR)$(libdir)/ecore_drm/bin/$(MODULE_ARCH)/ecore_drm_launch$(EXEEXT) || true;
55
56endif
diff --git a/src/bin/ecore_drm/ecore_drm_launch.c b/src/bin/ecore_drm/ecore_drm_launch.c
new file mode 100644
index 0000000000..14c3ad720a
--- /dev/null
+++ b/src/bin/ecore_drm/ecore_drm_launch.c
@@ -0,0 +1,407 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5/* standard headers */
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <string.h>
10#include <limits.h>
11#include <fcntl.h>
12#include <errno.h>
13#include <signal.h>
14#include <sys/types.h>
15#include <sys/socket.h>
16#include <sys/epoll.h>
17#include <sys/ioctl.h>
18/* #include <syslog.h> */
19/* #include <pwd.h> */
20
21/* #include <linux/major.h> */
22/* #include <linux/vt.h> */
23/* #include <linux/kd.h> */
24
25#include <xf86drm.h>
26#include <xf86drmMode.h>
27#include <drm_fourcc.h>
28
29#include <Eina.h>
30#include <Ecore_Drm.h>
31
32#define RIGHTS_LEN CMSG_LEN(sizeof(int))
33
34#define IOVSET(_iov, _addr, _len) \
35 (_iov)->iov_base = (void *)(_addr); \
36 (_iov)->iov_len = (_len);
37
38/* local prototypes */
39static int _send_msg(int opcode, int fd, void *data, size_t bytes);
40
41/* local variables */
42static struct cmsghdr *cmsgptr = NULL;
43static int _read_fd = -1;
44static int _write_fd = -1;
45
46static int
47_open_device(const char *device)
48{
49 int fd = -1, ret = ECORE_DRM_OP_SUCCESS;
50
51 if (!device)
52 {
53 ret = ECORE_DRM_OP_FAILURE;
54 _send_msg(ECORE_DRM_OP_DEVICE_OPEN, fd, &ret, sizeof(int));
55 return ret;
56 }
57
58 fprintf(stderr, "Launcher Trying to Open Device: %s\n", device);
59
60 if ((fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
61 {
62 fprintf(stderr, "Failed to Open Device: %s: %m\n", device);
63 ret = ECORE_DRM_OP_FAILURE;
64 }
65 else
66 fprintf(stderr, "Launcher Opened Device: %s %d\n", device, fd);
67
68 _send_msg(ECORE_DRM_OP_DEVICE_OPEN, fd, &ret, sizeof(int));
69
70 return ret;
71}
72
73static int
74_close_device(int fd)
75{
76 int ret = ECORE_DRM_OP_SUCCESS;
77
78 if (!fd)
79 {
80 ret = ECORE_DRM_OP_FAILURE;
81 _send_msg(ECORE_DRM_OP_DEVICE_CLOSE, fd, &ret, sizeof(int));
82 return ret;
83 }
84
85 close(fd);
86
87 _send_msg(ECORE_DRM_OP_DEVICE_CLOSE, fd, &ret, sizeof(int));
88
89 return ret;
90}
91
92static int
93_open_tty(const char *name)
94{
95 int fd = -1, ret = ECORE_DRM_OP_SUCCESS;
96 /* struct stat st; */
97
98 if (!name) goto fail;
99
100 fprintf(stderr, "Launcher Trying to Open Tty: %s\n", name);
101
102 if ((fd = open(name, O_RDWR | O_NOCTTY)) < 0)
103 {
104 fprintf(stderr, "Failed to Open Tty: %s: %m\n", name);
105 goto fail;
106 }
107 else
108 fprintf(stderr, "Launcher Opened Tty: %s %d\n", name, fd);
109
110 /* if ((fstat(fd, &st) == -1) || */
111 /* (major(st.st_rdev) != TTY_MAJOR) || (minor(st.st_rdev) == 0)) */
112 /* { */
113 /* fprintf(stderr, "%d is Not a Tty\n", fd); */
114 /* goto fail; */
115 /* } */
116
117 _send_msg(ECORE_DRM_OP_TTY_OPEN, fd, &ret, sizeof(int));
118
119 return ret;
120
121fail:
122 if (fd > -1) close(fd);
123 fd = -1;
124 ret = ECORE_DRM_OP_FAILURE;
125 _send_msg(ECORE_DRM_OP_DEVICE_OPEN, fd, &ret, sizeof(int));
126 return ret;
127}
128
129static int
130_drop_master(int fd)
131{
132 int ret = ECORE_DRM_OP_SUCCESS;
133
134 fprintf(stderr, "Drop Master: %d\n", fd);
135
136 if (drmDropMaster(fd) != 0)
137 {
138 ret = ECORE_DRM_OP_FAILURE;
139 fprintf(stderr, "\tFailed to drop master: %m\n");
140 }
141
142 _send_msg(ECORE_DRM_OP_DEVICE_MASTER_DROP, fd, &ret, sizeof(int));
143
144 close(fd);
145
146 return ret;
147}
148
149static int
150_set_master(int fd)
151{
152 int ret = ECORE_DRM_OP_SUCCESS;
153
154 fprintf(stderr, "Set Master: %d\n", fd);
155
156 if (drmSetMaster(fd) != 0)
157 {
158 ret = ECORE_DRM_OP_FAILURE;
159 fprintf(stderr, "\tFailed to set master: %m\n");
160 }
161
162 _send_msg(ECORE_DRM_OP_DEVICE_MASTER_SET, fd, &ret, sizeof(int));
163
164 close(fd);
165
166 return ret;
167}
168
169static int
170_read_fd_get(void)
171{
172 char *ev, *end;
173 int fd = -1, flags = -1;
174
175 if (!(ev = getenv("ECORE_DRM_LAUNCHER_SOCKET_READ")))
176 return -1;
177
178 fd = strtol(ev, &end, 0);
179 if (*end != '\0') return -1;
180
181 flags = fcntl(fd, F_GETFD);
182 if (flags < 0) return -1;
183
184 fprintf(stderr, "Got Read FD: %d\n", fd);
185
186 return fd;
187}
188
189static int
190_write_fd_get(void)
191{
192 char *ev, *end;
193 int fd = -1, flags = -1;
194
195 if (!(ev = getenv("ECORE_DRM_LAUNCHER_SOCKET_WRITE")))
196 return -1;
197
198 fd = strtol(ev, &end, 0);
199 if (*end != '\0') return -1;
200
201 flags = fcntl(fd, F_GETFD);
202 if (flags < 0) return -1;
203
204 fprintf(stderr, "Got Write FD: %d\n", fd);
205
206 return fd;
207}
208
209static int
210_send_msg(int opcode, int fd, void *data, size_t bytes)
211{
212 Ecore_Drm_Message dmsg;
213 struct iovec iov[2];
214 struct msghdr msg;
215 ssize_t size;
216
217 /* send a message to the calling process */
218 /* 'fd' is the fd to send */
219
220 memset(&dmsg, 0, sizeof(dmsg));
221
222 IOVSET(iov + 0, &dmsg, sizeof(dmsg));
223 IOVSET(iov + 1, &data, bytes);
224
225 dmsg.opcode = opcode;
226 dmsg.size = bytes;
227
228 msg.msg_name = NULL;
229 msg.msg_namelen = 0;
230 msg.msg_iov = iov;
231 msg.msg_iovlen = 2;
232 msg.msg_flags = 0;
233
234 if ((!cmsgptr) && (!(cmsgptr = malloc(RIGHTS_LEN))))
235 return -1;
236
237 cmsgptr->cmsg_level = SOL_SOCKET;
238 cmsgptr->cmsg_type = SCM_RIGHTS;
239 cmsgptr->cmsg_len = RIGHTS_LEN;
240
241 msg.msg_control = cmsgptr;
242 msg.msg_controllen = RIGHTS_LEN;
243
244 fprintf(stderr, "Launcher Sending FD: %d\n", fd);
245 *((int *)CMSG_DATA(cmsgptr)) = fd;
246
247 errno = 0;
248 size = sendmsg(_write_fd, &msg, MSG_EOR);
249 if (errno != 0)
250 {
251 fprintf(stderr, "Failed to send message: %s", strerror(errno));
252 return -1;
253 }
254
255 fprintf(stderr, "Launcher Wrote %li to %d\n", size, _write_fd);
256
257 return size;
258}
259
260static int
261_recv_msg(void)
262{
263 int fd = -1;
264 Ecore_Drm_Message dmsg;
265 struct iovec iov[2];
266 struct msghdr msg;
267 struct cmsghdr *cmsg = NULL;
268 char data[BUFSIZ];
269 ssize_t size;
270
271 fprintf(stderr, "Received Message\n");
272
273 memset(&dmsg, 0, sizeof(dmsg));
274 memset(&data, 0, sizeof(data));
275
276 IOVSET(iov + 0, &dmsg, sizeof(dmsg));
277 IOVSET(iov + 1, &data, sizeof(data));
278
279 msg.msg_name = NULL;
280 msg.msg_namelen = 0;
281 msg.msg_iov = iov;
282 msg.msg_iovlen = 2;
283 msg.msg_flags = 0;
284
285 if ((!cmsgptr) && (!(cmsgptr = malloc(RIGHTS_LEN))))
286 return -1;
287
288 msg.msg_control = cmsgptr;
289 msg.msg_controllen = RIGHTS_LEN;
290
291 errno = 0;
292 size = recvmsg(_read_fd, &msg, 0);
293 if (errno != 0)
294 {
295 fprintf(stderr, "Failed to receive message: %m\n");
296 return -1;
297 }
298
299 fprintf(stderr, "\tReceived %li bytes from %d\n", size, _read_fd);
300
301 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
302 cmsg = CMSG_NXTHDR(&msg, cmsg))
303 {
304 if (cmsg->cmsg_level != SOL_SOCKET)
305 continue;
306
307 switch (cmsg->cmsg_type)
308 {
309 case SCM_RIGHTS:
310 fd = *((int *)CMSG_DATA(cmsg));
311 switch (dmsg.opcode)
312 {
313 case ECORE_DRM_OP_DEVICE_OPEN:
314 fprintf(stderr, "Open Device: %s\n", (char *)data);
315 _open_device((char *)data);
316 break;
317 case ECORE_DRM_OP_DEVICE_CLOSE:
318 fprintf(stderr, "Close Device: %d\n", fd);
319 _close_device(fd);
320 case ECORE_DRM_OP_TTY_OPEN:
321 fprintf(stderr, "Open Tty: %s\n", (char *)data);
322 _open_tty((char *)data);
323 break;
324 case ECORE_DRM_OP_DEVICE_MASTER_DROP:
325 fprintf(stderr, "Drop Master: %d\n", fd);
326 _drop_master(fd);
327 break;
328 case ECORE_DRM_OP_DEVICE_MASTER_SET:
329 fprintf(stderr, "Set Master\n");
330 _set_master(fd);
331 break;
332 default:
333 fprintf(stderr, "Unhandled Opcode: %d\n", dmsg.opcode);
334 break;
335 }
336 break;
337 default:
338 fprintf(stderr, "Unhandled message type: %d\n", cmsg->cmsg_type);
339 return -1;
340 break;
341 }
342 }
343
344 return size;
345}
346
347int
348main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
349{
350 struct epoll_event ev, events[1];
351 int ret, i, _epoll_fd = -1;
352
353 setvbuf(stdout, NULL, _IONBF, 0);
354 setvbuf(stderr, NULL, _IONBF, 0);
355
356 fprintf(stderr, "Spartacus Is Alive\n");
357
358 _read_fd = _read_fd_get();
359 if (_read_fd < 0) return EXIT_FAILURE;
360
361 _write_fd = _write_fd_get();
362 if (_write_fd < 0) return EXIT_FAILURE;
363
364 fprintf(stderr, "Creating Epoll\n");
365 _epoll_fd = epoll_create(1);
366
367 memset(&ev, 0, sizeof(ev));
368 ev.events = EPOLLIN;
369 ev.data.fd = _read_fd;
370
371 if (epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, _read_fd, &ev) < 0)
372 {
373 return EXIT_FAILURE;
374 }
375
376 memset(&events, 0, sizeof(events));
377
378 while (1)
379 {
380 ret = epoll_wait(_epoll_fd, events, sizeof(events) / sizeof(struct epoll_event), -1);
381 if (ret < 0)
382 {
383 fprintf(stderr, "Epoll Failed: %m\n");
384 return EXIT_FAILURE;
385 }
386
387 for (i = 0; i < ret; i++)
388 {
389 fprintf(stderr, "Epoll Event on: %d\n", events[i].data.fd);
390 if (events[i].data.fd != _read_fd) continue;
391
392 if (events[i].events & EPOLLIN)
393 {
394 fprintf(stderr, "Epoll Data In\n");
395 _recv_msg();
396 }
397 else if (events[i].events & EPOLLERR)
398 {
399 fprintf(stderr, "Epoll Data Error\n");
400 }
401 }
402 }
403
404 fprintf(stderr, "Spartacus Is Dead\n");
405
406 return EXIT_SUCCESS;
407}
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..7e526f726a
--- /dev/null
+++ b/src/lib/ecore_drm/ecore_drm_device.c
@@ -0,0 +1,584 @@
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->format = 0;
273 dev->use_hw_accel = EINA_FALSE;
274 }
275 }
276
277 /* release device reference */
278 udev_device_unref(tmpdevice);
279
280 return dev;
281}
282
283/**
284 * Free an Ecore_Drm_Device
285 *
286 * This function will cleanup and free any previously allocated Ecore_Drm_Device.
287 *
288 * @param dev The Ecore_Drm_Device to free
289 *
290 * @ingroup Ecore_Drm_Device_Group
291 */
292EAPI void
293ecore_drm_device_free(Ecore_Drm_Device *dev)
294{
295 Ecore_Drm_Output *output;
296
297 /* check for valid device */
298 if (!dev) return;
299
300 /* free outputs */
301 EINA_LIST_FREE(dev->outputs, output)
302 ecore_drm_output_free(output);
303
304 /* free crtcs */
305 if (dev->crtcs) free(dev->crtcs);
306
307 /* free device name */
308 if (dev->drm.name) eina_stringshare_del(dev->drm.name);
309
310 /* free device path */
311 if (dev->drm.path) eina_stringshare_del(dev->drm.path);
312
313 /* free device seat */
314 if (dev->seat) eina_stringshare_del(dev->seat);
315
316 /* free structure */
317 free(dev);
318}
319
320/**
321 * Open an Ecore_Drm_Device
322 *
323 * This function will open an existing Ecore_Drm_Device for use.
324 *
325 * @param dev The Ecore_Drm_Device to try and open
326 *
327 * @return EINA_TRUE on success, EINA_FALSE on failure
328 *
329 * @ingroup Ecore_Drm_Device_Group
330 */
331EAPI Eina_Bool
332ecore_drm_device_open(Ecore_Drm_Device *dev)
333{
334 uint64_t caps;
335
336 /* check for valid device */
337 if ((!dev) || (!dev->drm.name)) return EINA_FALSE;
338
339 dev->drm.fd = open(dev->drm.name, O_RDWR);
340 if (dev->drm.fd < 0) return EINA_FALSE;
341
342 DBG("Opened Device %s : %d", dev->drm.name, dev->drm.fd);
343
344 if (!drmGetCap(dev->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &caps))
345 {
346 if (caps == 1)
347 dev->drm.clock = CLOCK_MONOTONIC;
348 else
349 dev->drm.clock = CLOCK_REALTIME;
350 }
351 else
352 {
353 ERR("Could not get device capabilities: %m");
354 }
355
356/* #ifdef HAVE_GBM */
357/* if (getenv("ECORE_DRM_HW_ACCEL")) */
358/* { */
359 /* Typically, gbm loads the dri driver However some versions of Mesa
360 * do not have libglapi symbols linked in the driver. Because of this,
361 * using hardware accel for our drm code Could fail with a
362 * message that the driver could not load. Let's be proactive and
363 * work around this for the user by preloading the glapi library */
364 /* dlopen("libglapi.so.0", (RTLD_LAZY | RTLD_GLOBAL)); */
365
366 /* if ((dev->gbm = gbm_create_device(dev->drm.fd))) */
367 /* { */
368 /* EGLint major, minor, visual; */
369 /* const EGLint attribs[] = */
370 /* { */
371 /* EGL_SURFACE_TYPE, EGL_WINDOW_BIT, */
372 /* EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, */
373 /* EGL_BLUE_SIZE, 1, EGL_ALPHA_SIZE, 0, */
374 /* EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE */
375 /* }; */
376
377 /* dev->use_hw_accel = EINA_TRUE; */
378 /* dev->format = GBM_FORMAT_XRGB8888; */
379
380 /* dev->egl.disp = eglGetDisplay(dev->gbm); */
381 /* if (dev->egl.disp == EGL_NO_DISPLAY) */
382 /* { */
383 /* ERR("Could not get egl display"); */
384 /* goto init_software; */
385 /* } */
386
387 /* if (!eglInitialize(dev->egl.disp, &major, &minor)) */
388 /* { */
389 /* ERR("Could not initialize egl"); */
390 /* goto init_software; */
391 /* } */
392
393 /* visual = dev->format; */
394 /* if (!_ecore_drm_device_egl_config_get(dev, attribs, &visual)) */
395 /* { */
396 /* ERR("Could not get egl config"); */
397 /* goto init_software; */
398 /* } */
399 /* } */
400 /* else */
401 /* { */
402 /* WRN("Failed to create gbm device"); */
403 /* goto init_software; */
404 /* } */
405 /* } */
406 /* else */
407/* #endif */
408 /* { */
409 /* TODO: init software */
410/* init_software: */
411/* DBG("Init Software Engine"); */
412/* #ifdef HAVE_GBM */
413/* if (dev->egl.disp) */
414/* { */
415/* eglMakeCurrent(dev->egl.disp, EGL_NO_SURFACE, EGL_NO_SURFACE, */
416/* EGL_NO_CONTEXT); */
417/* eglTerminate(dev->egl.disp); */
418/* eglReleaseThread(); */
419/* } */
420
421/* if (dev->gbm) gbm_device_destroy(dev->gbm); */
422/* dev->gbm = NULL; */
423/* #endif */
424/* } */
425
426 dev->drm.hdlr =
427 ecore_main_fd_handler_add(dev->drm.fd, ECORE_FD_READ,
428 _ecore_drm_device_cb_event, dev, NULL, NULL);
429
430 dev->drm.idler =
431 ecore_idle_enterer_add(_ecore_drm_device_cb_idle, dev);
432
433 return EINA_TRUE;
434}
435
436/**
437 * Close an Ecore_Drm_Device
438 *
439 * This function will close a previously opened Ecore_Drm_Device
440 *
441 * @param dev The Ecore_Drm_Device to free
442 *
443 * @return EINA_TRUE on success, EINA_FALSE on failure
444 *
445 * @ingroup Ecore_Drm_Device_Group
446 */
447EAPI Eina_Bool
448ecore_drm_device_close(Ecore_Drm_Device *dev)
449{
450 /* check for valid device */
451 if (!dev) return EINA_FALSE;
452
453/* #ifdef HAVE_GBM */
454/* if (dev->use_hw_accel) */
455/* { */
456/* if (dev->egl.disp) */
457/* { */
458/* eglMakeCurrent(dev->egl.disp, EGL_NO_SURFACE, EGL_NO_SURFACE, */
459/* EGL_NO_CONTEXT); */
460/* eglTerminate(dev->egl.disp); */
461/* eglReleaseThread(); */
462/* } */
463
464/* if (dev->gbm) gbm_device_destroy(dev->gbm); */
465/* dev->gbm = NULL; */
466/* } */
467/* #endif */
468
469 if (dev->drm.hdlr) ecore_main_fd_handler_del(dev->drm.hdlr);
470 dev->drm.hdlr = NULL;
471
472 close(dev->drm.fd);
473
474 /* reset device fd */
475 dev->drm.fd = -1;
476
477 /* free(data); */
478
479 return EINA_TRUE;
480}
481
482/**
483 * Get if a given Ecore_Drm_Device is master
484 *
485 * This function will check if the given drm device is set to master
486 *
487 * @param dev The Ecore_Drm_Device to check
488 *
489 * @return EINA_TRUE if device is master, EINA_FALSE otherwise
490 *
491 * @ingroup Ecore_Drm_Device_Group
492 */
493EAPI Eina_Bool
494ecore_drm_device_master_get(Ecore_Drm_Device *dev)
495{
496 /* drm_magic_t mag; */
497
498 /* check for valid device */
499 if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
500
501 /* FIXME: Remote this to the slave process !! */
502
503 /* get if we are master or not */
504 /* if ((drmGetMagic(dev->drm.fd, &mag) == 0) && */
505 /* (drmAuthMagic(dev->drm.fd, mag) == 0)) */
506 /* return EINA_TRUE; */
507
508 return EINA_FALSE;
509}
510
511/**
512 * Set a given Ecore_Drm_Device to master
513 *
514 * This function will attempt to set a given drm device to be master
515 *
516 * @param dev The Ecore_Drm_Device to set
517 *
518 * @return EINA_TRUE on success, EINA_FALSE on failure
519 *
520 * @ingroup Ecore_Drm_Device_Group
521 */
522EAPI Eina_Bool
523ecore_drm_device_master_set(Ecore_Drm_Device *dev)
524{
525 Eina_Bool ret = EINA_FALSE;
526 int dfd;
527
528 /* check for valid device */
529 if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
530
531 DBG("Set Master On Fd: %d", dev->drm.fd);
532
533 /* try to close the device */
534 _ecore_drm_message_send(ECORE_DRM_OP_DEVICE_MASTER_SET, dev->drm.fd,
535 NULL, 0);
536
537 /* get the result of the close operation */
538 ret = _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_MASTER_SET, &dfd,
539 NULL, 0);
540 if (!ret) return EINA_FALSE;
541
542 return EINA_TRUE;
543}
544
545/**
546 * Tell a given Ecore_Drm_Device to stop being master
547 *
548 * This function will attempt to ask a drm device to stop being master
549 *
550 * @param dev The Ecore_Drm_Device to set
551 *
552 * @return EINA_TRUE on success, EINA_FALSE on failure
553 *
554 * @ingroup Ecore_Drm_Device_Group
555 */
556EAPI Eina_Bool
557ecore_drm_device_master_drop(Ecore_Drm_Device *dev)
558{
559 Eina_Bool ret = EINA_FALSE;
560 int dfd;
561
562 /* check for valid device */
563 if ((!dev) || (dev->drm.fd < 0)) return EINA_FALSE;
564
565 DBG("Drop Master On Fd: %d", dev->drm.fd);
566
567 /* try to close the device */
568 _ecore_drm_message_send(ECORE_DRM_OP_DEVICE_MASTER_DROP, dev->drm.fd,
569 NULL, 0);
570
571 /* get the result of the close operation */
572 ret = _ecore_drm_message_receive(ECORE_DRM_OP_DEVICE_MASTER_DROP, &dfd,
573 NULL, 0);
574 if (!ret) return EINA_FALSE;
575
576 return EINA_TRUE;
577}
578
579EAPI int
580ecore_drm_device_fd_get(Ecore_Drm_Device *dev)
581{
582 if (!dev) return -1;
583 return dev->drm.fd;
584}
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..c363d02553
--- /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 EINA_UNUSED)
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 EINA_UNUSED)
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..5e41be7669
--- /dev/null
+++ b/src/lib/ecore_drm/ecore_drm_private.h
@@ -0,0 +1,283 @@
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# define NUM_FRAME_BUFFERS 2
35
36# ifndef DRM_MAJOR
37# define DRM_MAJOR 226
38# endif
39
40# ifndef DRM_CAP_TIMESTAMP_MONOTONIC
41# define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
42# endif
43
44# ifdef ECORE_DRM_DEFAULT_LOG_COLOR
45# undef ECORE_DRM_DEFAULT_LOG_COLOR
46# endif
47# define ECORE_DRM_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
48
49# define EVDEV_SEAT_POINTER (1 << 0)
50# define EVDEV_SEAT_KEYBOARD (1 << 1)
51# define EVDEV_SEAT_TOUCH (1 << 2)
52
53# ifdef ERR
54# undef ERR
55# endif
56# ifdef DBG
57# undef DBG
58# endif
59# ifdef INF
60# undef INF
61# endif
62# ifdef WRN
63# undef WRN
64# endif
65# ifdef CRIT
66# undef CRIT
67# endif
68
69extern int _ecore_drm_log_dom;
70
71/* undef this for non-testing builds */
72# define LOG_TO_FILE
73
74# ifdef LOG_TO_FILE
75extern FILE *lg;
76
77# define ERR(...) \
78 EINA_LOG_DOM_ERR(_ecore_drm_log_dom, __VA_ARGS__); \
79 fflush(lg);
80
81# define DBG(...) \
82 EINA_LOG_DOM_DBG(_ecore_drm_log_dom, __VA_ARGS__); \
83 fflush(lg);
84
85# define INF(...) \
86 EINA_LOG_DOM_INFO(_ecore_drm_log_dom, __VA_ARGS__); \
87 fflush(lg);
88
89# define WRN(...) \
90 EINA_LOG_DOM_WARN(_ecore_drm_log_dom, __VA_ARGS__); \
91 fflush(lg);
92
93# define CRIT(...) \
94 EINA_LOG_DOM_CRIT(_ecore_drm_log_dom, __VA_ARGS__); \
95 fflush(lg);
96
97# else
98# define ERR(...) EINA_LOG_DOM_ERR(_ecore_drm_log_dom, __VA_ARGS__)
99# define DBG(...) EINA_LOG_DOM_DBG(_ecore_drm_log_dom, __VA_ARGS__)
100# define INF(...) EINA_LOG_DOM_INFO(_ecore_drm_log_dom, __VA_ARGS__)
101# define WRN(...) EINA_LOG_DOM_WARN(_ecore_drm_log_dom, __VA_ARGS__)
102# define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_drm_log_dom, __VA_ARGS__)
103# endif
104
105extern struct udev *udev;
106
107struct _Ecore_Drm_Output_Mode
108{
109 unsigned int flags;
110 int width, height;
111 unsigned int refresh;
112 drmModeModeInfo info;
113};
114
115struct _Ecore_Drm_Output
116{
117 Ecore_Drm_Device *dev;
118 unsigned int crtc_id;
119 unsigned int conn_id;
120 drmModeCrtcPtr crtc;
121
122 int x, y;
123 int drm_fd;
124
125 Eina_Bool need_repaint : 1;
126 Eina_Bool repaint_scheduled : 1;
127
128 Eina_Bool pending_flip : 1;
129 Eina_Bool pending_vblank : 1;
130
131 const char *make, *model, *name;
132 unsigned int subpixel;
133
134 Ecore_Drm_Output_Mode *current_mode;
135 Eina_List *modes;
136
137 Ecore_Drm_Fb *current, *next;
138 Ecore_Drm_Fb *dumb[NUM_FRAME_BUFFERS];
139
140/* # ifdef HAVE_GBM */
141/* struct gbm_surface *surface; */
142/* struct gbm_bo *cursor[NUM_FRAME_BUFFERS]; */
143/* struct */
144/* { */
145/* EGLSurface surface; */
146/* } egl; */
147/* # endif */
148
149 /* TODO: finish */
150};
151
152struct _Ecore_Drm_Seat
153{
154// struct libinput_seat *seat;
155 const char *name;
156 Ecore_Drm_Input *input;
157 Eina_List *devices;
158};
159
160struct _Ecore_Drm_Input
161{
162 int fd;
163 const char *seat;
164 struct udev_monitor *monitor;
165 Ecore_Fd_Handler *hdlr;
166 Ecore_Drm_Device *dev;
167
168 Eina_Bool enabled : 1;
169 Eina_Bool suspended : 1;
170};
171
172struct _Ecore_Drm_Evdev
173{
174 Ecore_Drm_Seat *seat;
175 /* struct libinput *linput; */
176 /* struct libinput_device *dev; */
177 const char *name, *path;
178 int fd;
179
180 struct
181 {
182 int min_x, min_y;
183 int max_x, max_y;
184 int x, y;
185 } abs;
186
187 Ecore_Drm_Evdev_Event_Type pending_event;
188 Ecore_Drm_Evdev_Capabilities caps;
189 Ecore_Drm_Seat_Capabilities seat_caps;
190
191 void (*event_process)(Ecore_Drm_Evdev *dev, struct input_event *event, int count);
192
193 Ecore_Fd_Handler *hdlr;
194};
195
196struct _Ecore_Drm_Sprite
197{
198 Ecore_Drm_Fb *current_fb, *next_fb;
199 Ecore_Drm_Output *output;
200
201 int drm_fd;
202
203 unsigned int crtcs;
204 unsigned int plane_id;
205
206 struct
207 {
208 int x, y;
209 unsigned int w, h;
210 } src, dest;
211
212 unsigned int num_formats;
213 unsigned int formats[];
214};
215
216struct _Ecore_Drm_Device
217{
218 int id;
219 const char *seat;
220
221 struct
222 {
223 int fd;
224 const char *name;
225 const char *path;
226 clockid_t clock;
227 Ecore_Fd_Handler *hdlr;
228 Ecore_Idle_Enterer *idler;
229 } drm;
230
231 unsigned int min_width, min_height;
232 unsigned int max_width, max_height;
233
234 unsigned int crtc_count;
235 unsigned int *crtcs;
236 unsigned int crtc_allocator;
237
238 Eina_List *seats;
239 Eina_List *inputs;
240 Eina_List *outputs;
241 Eina_List *sprites;
242
243 struct
244 {
245 int fd;
246 const char *name;
247 Ecore_Event_Handler *event_hdlr;
248 } tty;
249
250 unsigned int format;
251 Eina_Bool use_hw_accel : 1;
252 Eina_Bool cursors_broken : 1;
253
254/* #ifdef HAVE_GBM */
255/* struct gbm_device *gbm; */
256/* struct */
257/* { */
258/* EGLDisplay disp; */
259/* EGLContext ctxt; */
260/* EGLConfig cfg; */
261/* } egl; */
262/* #endif */
263};
264
265void _ecore_drm_message_send(int opcode, int fd, void *data, size_t bytes);
266Eina_Bool _ecore_drm_message_receive(int opcode, int *fd, void **data, size_t bytes);
267
268Ecore_Drm_Evdev *_ecore_drm_evdev_device_create(Ecore_Drm_Seat *seat, const char *path, int fd);
269void _ecore_drm_evdev_device_destroy(Ecore_Drm_Evdev *evdev);
270/* int _ecore_drm_evdev_event_process(struct libinput_event *event); */
271
272Ecore_Drm_Fb *_ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height);
273void _ecore_drm_fb_destroy(Ecore_Drm_Fb *fb);
274
275/* #ifdef HAVE_GBM */
276/* Ecore_Drm_Fb *_ecore_drm_fb_bo_get(Ecore_Drm_Device *dev, struct gbm_bo *bo); */
277/* #endif */
278
279void _ecore_drm_output_fb_release(Ecore_Drm_Output *output, Ecore_Drm_Fb *fb);
280void _ecore_drm_output_repaint_start(Ecore_Drm_Output *output);
281void _ecore_drm_output_frame_finish(Ecore_Drm_Output *output);
282
283#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 */