summaryrefslogtreecommitdiff
path: root/src/lib/ecore_drm/ecore_drm.c
diff options
context:
space:
mode:
authorChris Michael <cp.michael@samsung.com>2014-03-06 09:43:48 +0000
committerChris Michael <cp.michael@samsung.com>2014-03-06 10:57:26 +0000
commit3762e85c3967a7a7574c83bf6d550d58e58d90fc (patch)
tree48e695cf560924cf0b800f682371dfe1eb74de7e /src/lib/ecore_drm/ecore_drm.c
parent0f1883df9a978d686971bba9f1450b7eb7a3fd84 (diff)
ecore-drm: Add Ecore_Drm code
@feature: Add Ecore_Drm library code for setting up drm card, outputs, virtual terminals, framebuffers, and input for use with ecore_evas drm code. Signed-off-by: Chris Michael <cp.michael@samsung.com>
Diffstat (limited to 'src/lib/ecore_drm/ecore_drm.c')
-rw-r--r--src/lib/ecore_drm/ecore_drm.c414
1 files changed, 414 insertions, 0 deletions
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}