blob: 1d04c060968f2ea13b2f3aeca74dc462720b9438 [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
2 * Copyright © 2008-2010 Kristian Høgsberg
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <fcntl.h>
23#include <unistd.h>
24
25#include <signal.h>
Jesse Barnesf2912fa2010-11-08 11:51:12 -080026#include <linux/kd.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <linux/vt.h>
28#include <linux/input.h>
29
30#define GL_GLEXT_PROTOTYPES
31#define EGL_EGLEXT_PROTOTYPES
32#include <GLES2/gl2.h>
33#include <GLES2/gl2ext.h>
34#include <EGL/egl.h>
35#include <EGL/eglext.h>
36
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040037#include "compositor.h"
38
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040039struct drm_compositor {
40 struct wlsc_compositor base;
41
42 struct udev *udev;
43 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040044
Kristian Høgsbergcaa64422010-12-01 16:52:15 -050045 /* tty handling state */
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040046 int tty_fd;
47 uint32_t vt_active : 1;
48
49 struct termios terminal_attributes;
50 struct wl_event_source *tty_input_source;
51 struct wl_event_source *enter_vt_source;
52 struct wl_event_source *leave_vt_source;
53};
54
55struct drm_output {
56 struct wlsc_output base;
57
58 drmModeModeInfo mode;
59 uint32_t crtc_id;
60 uint32_t connector_id;
61 GLuint rbo[2];
62 uint32_t fb_id[2];
63 EGLImageKHR image[2];
64 uint32_t current;
65};
66
67struct drm_input {
68 struct wlsc_input_device base;
69};
70
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040071struct evdev_input_device {
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040072 struct drm_input *master;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040073 struct wl_event_source *source;
74 int tool, new_x, new_y;
75 int base_x, base_y;
76 int fd;
77};
78
79static void evdev_input_device_data(int fd, uint32_t mask, void *data)
80{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040081 struct drm_compositor *c;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040082 struct evdev_input_device *device = data;
83 struct input_event ev[8], *e, *end;
84 int len, value, dx, dy, absolute_event;
85 int x, y;
Kristian Høgsberg808fd412010-07-20 17:06:19 -040086 uint32_t time;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040087
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040088 c = (struct drm_compositor *) device->master->base.ec;
89 if (!c->vt_active)
90 return;
91
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040092 dx = 0;
93 dy = 0;
94 absolute_event = 0;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040095 x = device->master->base.x;
96 y = device->master->base.y;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040097
98 len = read(fd, &ev, sizeof ev);
99 if (len < 0 || len % sizeof e[0] != 0) {
100 /* FIXME: handle error... reopen device? */;
101 return;
102 }
103
104 e = ev;
105 end = (void *) ev + len;
106 for (e = ev; e < end; e++) {
107 /* Get the signed value, earlier kernels had this as unsigned */
108 value = e->value;
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400109 time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400110
111 switch (e->type) {
112 case EV_REL:
113 switch (e->code) {
114 case REL_X:
115 dx += value;
116 break;
117
118 case REL_Y:
119 dy += value;
120 break;
121 }
122 break;
123
124 case EV_ABS:
125 absolute_event = 1;
126 switch (e->code) {
127 case ABS_X:
128 if (device->new_x) {
129 device->base_x = x - value;
130 device->new_x = 0;
131 }
132 x = device->base_x + value;
133 break;
134 case ABS_Y:
135 if (device->new_y) {
136 device->base_y = y - value;
137 device->new_y = 0;
138 }
139 y = device->base_y + value;
140 break;
141 }
142 break;
143
144 case EV_KEY:
145 if (value == 2)
146 break;
147
148 switch (e->code) {
149 case BTN_TOUCH:
150 case BTN_TOOL_PEN:
151 case BTN_TOOL_RUBBER:
152 case BTN_TOOL_BRUSH:
153 case BTN_TOOL_PENCIL:
154 case BTN_TOOL_AIRBRUSH:
155 case BTN_TOOL_FINGER:
156 case BTN_TOOL_MOUSE:
157 case BTN_TOOL_LENS:
158 if (device->tool == 0 && value) {
159 device->new_x = 1;
160 device->new_y = 1;
161 }
162 device->tool = value ? e->code : 0;
163 break;
164
165 case BTN_LEFT:
166 case BTN_RIGHT:
167 case BTN_MIDDLE:
168 case BTN_SIDE:
169 case BTN_EXTRA:
170 case BTN_FORWARD:
171 case BTN_BACK:
172 case BTN_TASK:
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400173 notify_button(&device->master->base,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400174 time, e->code, value);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400175 break;
176
177 default:
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400178 notify_key(&device->master->base,
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400179 time, e->code, value);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400180 break;
181 }
182 }
183 }
184
185 if (dx != 0 || dy != 0)
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400186 notify_motion(&device->master->base, time, x + dx, y + dy);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400187 if (absolute_event && device->tool)
Kristian Høgsberg808fd412010-07-20 17:06:19 -0400188 notify_motion(&device->master->base, time, x, y);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400189}
190
191static struct evdev_input_device *
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400192evdev_input_device_create(struct drm_input *master,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400193 struct wl_display *display, const char *path)
194{
195 struct evdev_input_device *device;
196 struct wl_event_loop *loop;
197
198 device = malloc(sizeof *device);
199 if (device == NULL)
200 return NULL;
201
202 device->tool = 1;
203 device->new_x = 1;
204 device->new_y = 1;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400205 device->master = master;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400206
207 device->fd = open(path, O_RDONLY);
208 if (device->fd < 0) {
209 free(device);
210 fprintf(stderr, "couldn't create pointer for %s: %m\n", path);
211 return NULL;
212 }
213
214 loop = wl_display_get_event_loop(display);
215 device->source = wl_event_loop_add_fd(loop, device->fd,
216 WL_EVENT_READABLE,
217 evdev_input_device_data, device);
218 if (device->source == NULL) {
219 close(device->fd);
220 free(device);
221 return NULL;
222 }
223
224 return device;
225}
226
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400227static void
228drm_input_create(struct drm_compositor *c)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400229{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400230 struct drm_input *input;
231 struct udev_enumerate *e;
232 struct udev_list_entry *entry;
233 struct udev_device *device;
234 const char *path;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400235
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400236 input = malloc(sizeof *input);
237 if (input == NULL)
238 return;
239
240 memset(input, 0, sizeof *input);
241 wlsc_input_device_init(&input->base, &c->base);
242
243 e = udev_enumerate_new(c->udev);
244 udev_enumerate_add_match_subsystem(e, "input");
245 udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1");
246 udev_enumerate_scan_devices(e);
247 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
248 path = udev_list_entry_get_name(entry);
249 device = udev_device_new_from_syspath(c->udev, path);
250 evdev_input_device_create(input, c->base.wl_display,
251 udev_device_get_devnode(device));
252 }
253 udev_enumerate_unref(e);
254
255 c->base.input_device = &input->base;
256}
257
258static void
259drm_compositor_present(struct wlsc_compositor *ec)
260{
261 struct drm_compositor *c = (struct drm_compositor *) ec;
262 struct drm_output *output;
263
264 wl_list_for_each(output, &ec->output_list, base.link) {
265 output->current ^= 1;
266
267 glFramebufferRenderbuffer(GL_FRAMEBUFFER,
268 GL_COLOR_ATTACHMENT0,
269 GL_RENDERBUFFER,
270 output->rbo[output->current]);
271
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400272 drmModePageFlip(c->base.drm.fd, output->crtc_id,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400273 output->fb_id[output->current ^ 1],
274 DRM_MODE_PAGE_FLIP_EVENT, output);
275 }
276}
277
278static void
279page_flip_handler(int fd, unsigned int frame,
280 unsigned int sec, unsigned int usec, void *data)
281{
282 struct wlsc_output *output = data;
283 struct wlsc_compositor *compositor = output->compositor;
284 uint32_t msecs;
285
286 msecs = sec * 1000 + usec / 1000;
287 wlsc_compositor_finish_frame(compositor, msecs);
288}
289
290static void
291on_drm_input(int fd, uint32_t mask, void *data)
292{
293 drmEventContext evctx;
294
295 memset(&evctx, 0, sizeof evctx);
296 evctx.version = DRM_EVENT_CONTEXT_VERSION;
297 evctx.page_flip_handler = page_flip_handler;
298 drmHandleEvent(fd, &evctx);
299}
300
301static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400302init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400303{
Kristian Høgsberg379b6782010-07-28 22:52:28 -0400304 EGLint major, minor;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400305 const char *extensions, *filename;
306 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -0400307 static const EGLint context_attribs[] = {
308 EGL_CONTEXT_CLIENT_VERSION, 2,
309 EGL_NONE
310 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400311
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400312 filename = udev_device_get_devnode(device);
313 fd = open(filename, O_RDWR);
314 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400315 /* Probably permissions error */
316 fprintf(stderr, "couldn't open %s, skipping\n",
317 udev_device_get_devnode(device));
318 return -1;
319 }
320
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400321 wlsc_drm_init(&ec->base, fd, filename);
322
323 ec->base.display = eglGetDRMDisplayMESA(ec->base.drm.fd);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400324 if (ec->base.display == NULL) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400325 fprintf(stderr, "failed to create display\n");
326 return -1;
327 }
328
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400329 if (!eglInitialize(ec->base.display, &major, &minor)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400330 fprintf(stderr, "failed to initialize display\n");
331 return -1;
332 }
333
Kristian Høgsberg379b6782010-07-28 22:52:28 -0400334 extensions = eglQueryString(ec->base.display, EGL_EXTENSIONS);
335 if (!strstr(extensions, "EGL_KHR_surfaceless_opengl")) {
336 fprintf(stderr, "EGL_KHR_surfaceless_opengl not available\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400337 return -1;
338 }
339
Darxus55973f22010-11-22 21:24:39 -0500340 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
341 fprintf(stderr, "failed to bind api EGL_OPENGL_ES_API\n");
342 return -1;
343 }
344
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -0400345 ec->base.context = eglCreateContext(ec->base.display, NULL,
346 EGL_NO_CONTEXT, context_attribs);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400347 if (ec->base.context == NULL) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400348 fprintf(stderr, "failed to create context\n");
349 return -1;
350 }
351
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400352 if (!eglMakeCurrent(ec->base.display, EGL_NO_SURFACE,
353 EGL_NO_SURFACE, ec->base.context)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400354 fprintf(stderr, "failed to make context current\n");
355 return -1;
356 }
357
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400358 return 0;
359}
360
361static drmModeModeInfo builtin_1024x768 = {
362 63500, /* clock */
363 1024, 1072, 1176, 1328, 0,
364 768, 771, 775, 798, 0,
365 59920,
366 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC,
367 0,
368 "1024x768"
369};
370
371static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400372create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400373 drmModeRes *resources,
374 drmModeConnector *connector)
375{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400376 struct drm_output *output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400377 drmModeEncoder *encoder;
378 drmModeModeInfo *mode;
379 int i, ret;
380 EGLint handle, stride, attribs[] = {
381 EGL_WIDTH, 0,
382 EGL_HEIGHT, 0,
Kristian Høgsbergb12fcce2010-08-24 17:34:23 -0400383 EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
384 EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SCANOUT_MESA,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400385 EGL_NONE
386 };
387
388 output = malloc(sizeof *output);
389 if (output == NULL)
390 return -1;
391
392 if (connector->count_modes > 0)
393 mode = &connector->modes[0];
394 else
395 mode = &builtin_1024x768;
396
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400397 encoder = drmModeGetEncoder(ec->base.drm.fd, connector->encoders[0]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400398 if (encoder == NULL) {
399 fprintf(stderr, "No encoder for connector.\n");
400 return -1;
401 }
402
403 for (i = 0; i < resources->count_crtcs; i++) {
404 if (encoder->possible_crtcs & (1 << i))
405 break;
406 }
407 if (i == resources->count_crtcs) {
408 fprintf(stderr, "No usable crtc for encoder.\n");
409 return -1;
410 }
411
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400412 memset(output, 0, sizeof *output);
413 wlsc_output_init(&output->base, &ec->base, 0, 0,
414 mode->hdisplay, mode->vdisplay);
415
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400416 output->crtc_id = resources->crtcs[i];
417 output->connector_id = connector->connector_id;
418 output->mode = *mode;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400419
420 drmModeFreeEncoder(encoder);
421
422 glGenRenderbuffers(2, output->rbo);
423 for (i = 0; i < 2; i++) {
424 glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
425
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400426 attribs[1] = output->base.width;
427 attribs[3] = output->base.height;
428 output->image[i] =
429 eglCreateDRMImageMESA(ec->base.display, attribs);
430 glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
431 output->image[i]);
432 eglExportDRMImageMESA(ec->base.display, output->image[i],
433 NULL, &handle, &stride);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400434
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400435 ret = drmModeAddFB(ec->base.drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400436 output->base.width, output->base.height,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400437 32, 32, stride, handle, &output->fb_id[i]);
438 if (ret) {
439 fprintf(stderr, "failed to add fb %d: %m\n", i);
440 return -1;
441 }
442 }
443
444 output->current = 0;
445 glFramebufferRenderbuffer(GL_FRAMEBUFFER,
446 GL_COLOR_ATTACHMENT0,
447 GL_RENDERBUFFER,
448 output->rbo[output->current]);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400449 ret = drmModeSetCrtc(ec->base.drm.fd, output->crtc_id,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400450 output->fb_id[output->current ^ 1], 0, 0,
451 &output->connector_id, 1, &output->mode);
452 if (ret) {
453 fprintf(stderr, "failed to set mode: %m\n");
454 return -1;
455 }
456
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400457 wl_list_insert(ec->base.output_list.prev, &output->base.link);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400458
459 return 0;
460}
461
462static int
Kristian Høgsberg61a82512010-10-26 11:26:44 -0400463create_outputs(struct drm_compositor *ec, int option_connector)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400464{
465 drmModeConnector *connector;
466 drmModeRes *resources;
467 int i;
468
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400469 resources = drmModeGetResources(ec->base.drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400470 if (!resources) {
471 fprintf(stderr, "drmModeGetResources failed\n");
472 return -1;
473 }
474
475 for (i = 0; i < resources->count_connectors; i++) {
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400476 connector = drmModeGetConnector(ec->base.drm.fd, resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400477 if (connector == NULL)
478 continue;
479
480 if (connector->connection == DRM_MODE_CONNECTED &&
481 (option_connector == 0 ||
482 connector->connector_id == option_connector))
483 if (create_output_for_connector(ec, resources, connector) < 0)
484 return -1;
485
486 drmModeFreeConnector(connector);
487 }
488
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400489 if (wl_list_empty(&ec->base.output_list)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400490 fprintf(stderr, "No currently active connector found.\n");
491 return -1;
492 }
493
494 drmModeFreeResources(resources);
495
496 return 0;
497}
498
499static void on_enter_vt(int signal_number, void *data)
500{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400501 struct drm_compositor *ec = data;
502 struct drm_output *output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400503 int ret;
504
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400505 ret = drmSetMaster(ec->base.drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400506 if (ret) {
507 fprintf(stderr, "failed to set drm master\n");
508 kill(0, SIGTERM);
509 return;
510 }
511
512 fprintf(stderr, "enter vt\n");
513
514 ioctl(ec->tty_fd, VT_RELDISP, VT_ACKACQ);
Jesse Barnesf2912fa2010-11-08 11:51:12 -0800515 ret = ioctl(ec->tty_fd, KDSETMODE, KD_GRAPHICS);
516 if (ret)
517 fprintf(stderr, "failed to set KD_GRAPHICS mode on console: %m\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400518 ec->vt_active = 1;
519
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400520 wl_list_for_each(output, &ec->base.output_list, base.link) {
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400521 ret = drmModeSetCrtc(ec->base.drm.fd, output->crtc_id,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400522 output->fb_id[output->current ^ 1], 0, 0,
523 &output->connector_id, 1, &output->mode);
524 if (ret)
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400525 fprintf(stderr,
526 "failed to set mode for connector %d: %m\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400527 output->connector_id);
528 }
529}
530
531static void on_leave_vt(int signal_number, void *data)
532{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400533 struct drm_compositor *ec = data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400534 int ret;
535
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400536 ret = drmDropMaster(ec->base.drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400537 if (ret) {
538 fprintf(stderr, "failed to drop drm master\n");
539 kill(0, SIGTERM);
540 return;
541 }
542
543 ioctl (ec->tty_fd, VT_RELDISP, 1);
Jesse Barnesf2912fa2010-11-08 11:51:12 -0800544 ret = ioctl(ec->tty_fd, KDSETMODE, KD_TEXT);
545 if (ret)
546 fprintf(stderr, "failed to set KD_TEXT mode on console: %m\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400547 ec->vt_active = 0;
548}
549
550static void
551on_tty_input(int fd, uint32_t mask, void *data)
552{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400553 struct drm_compositor *ec = data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400554
555 /* Ignore input to tty. We get keyboard events from evdev
556 */
557 tcflush(ec->tty_fd, TCIFLUSH);
558}
559
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400560static int setup_tty(struct drm_compositor *ec, struct wl_event_loop *loop)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400561{
562 struct termios raw_attributes;
563 struct vt_mode mode = { 0 };
Jesse Barnesf2912fa2010-11-08 11:51:12 -0800564 int ret;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400565
566 ec->tty_fd = open("/dev/tty0", O_RDWR | O_NOCTTY);
567 if (ec->tty_fd <= 0) {
568 fprintf(stderr, "failed to open active tty: %m\n");
569 return -1;
570 }
571
572 if (tcgetattr(ec->tty_fd, &ec->terminal_attributes) < 0) {
573 fprintf(stderr, "could not get terminal attributes: %m\n");
574 return -1;
575 }
576
577 /* Ignore control characters and disable echo */
578 raw_attributes = ec->terminal_attributes;
579 cfmakeraw(&raw_attributes);
580
581 /* Fix up line endings to be normal (cfmakeraw hoses them) */
582 raw_attributes.c_oflag |= OPOST | OCRNL;
583
584 if (tcsetattr(ec->tty_fd, TCSANOW, &raw_attributes) < 0)
585 fprintf(stderr, "could not put terminal into raw mode: %m\n");
586
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400587 ec->tty_input_source =
588 wl_event_loop_add_fd(loop, ec->tty_fd,
589 WL_EVENT_READABLE, on_tty_input, ec);
590
Jesse Barnesf2912fa2010-11-08 11:51:12 -0800591 ret = ioctl(ec->tty_fd, KDSETMODE, KD_GRAPHICS);
592 if (ret)
593 fprintf(stderr, "failed to set KD_GRAPHICS mode on tty: %m\n");
594
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400595 ec->vt_active = 1;
596 mode.mode = VT_PROCESS;
597 mode.relsig = SIGUSR1;
598 mode.acqsig = SIGUSR2;
599 if (!ioctl(ec->tty_fd, VT_SETMODE, &mode) < 0) {
600 fprintf(stderr, "failed to take control of vt handling\n");
601 }
602
603 ec->leave_vt_source =
604 wl_event_loop_add_signal(loop, SIGUSR1, on_leave_vt, ec);
605 ec->enter_vt_source =
606 wl_event_loop_add_signal(loop, SIGUSR2, on_enter_vt, ec);
607
608 return 0;
609}
610
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400611static int
612drm_authenticate(struct wlsc_compositor *c, uint32_t id)
613{
614 struct drm_compositor *ec = (struct drm_compositor *) c;
615
616 return drmAuthMagic(ec->base.drm.fd, id);
617}
618
Kristian Høgsbergcaa64422010-12-01 16:52:15 -0500619static void
620drm_destroy(struct wlsc_compositor *ec)
621{
622 struct drm_compositor *d = (struct drm_compositor *) ec;
623
624 if (tcsetattr(d->tty_fd, TCSANOW, &d->terminal_attributes) < 0)
625 fprintf(stderr,
626 "could not restore terminal to canonical mode\n");
627
628 free(ec);
629}
630
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400631struct wlsc_compositor *
Kristian Høgsberg61a82512010-10-26 11:26:44 -0400632drm_compositor_create(struct wl_display *display, int connector)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400633{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400634 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400635 struct udev_enumerate *e;
636 struct udev_list_entry *entry;
637 struct udev_device *device;
638 const char *path;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400639 struct wl_event_loop *loop;
640
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400641 ec = malloc(sizeof *ec);
642 if (ec == NULL)
643 return NULL;
644
645 memset(ec, 0, sizeof *ec);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400646 ec->udev = udev_new();
647 if (ec->udev == NULL) {
648 fprintf(stderr, "failed to initialize udev context\n");
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400649 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400650 }
651
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400652 e = udev_enumerate_new(ec->udev);
653 udev_enumerate_add_match_subsystem(e, "drm");
654 udev_enumerate_add_match_property(e, "WAYLAND_SEAT", "1");
655 udev_enumerate_scan_devices(e);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400656 device = NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400657 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
658 path = udev_list_entry_get_name(entry);
659 device = udev_device_new_from_syspath(ec->udev, path);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400660 break;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400661 }
662 udev_enumerate_unref(e);
663
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400664 if (device == NULL) {
665 fprintf(stderr, "no drm device found\n");
666 return NULL;
667 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400668
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400669 ec->base.wl_display = display;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400670 if (init_egl(ec, device) < 0) {
671 fprintf(stderr, "failed to initialize egl\n");
672 return NULL;
673 }
674
675 /* Can't init base class until we have a current egl context */
Kristian Høgsberga9468212010-06-14 21:03:11 -0400676 if (wlsc_compositor_init(&ec->base, display) < 0)
677 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400678
Kristian Høgsberg61a82512010-10-26 11:26:44 -0400679 if (create_outputs(ec, connector) < 0) {
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400680 fprintf(stderr, "failed to create output for %s\n", path);
681 return NULL;
682 }
683
684 drm_input_create(ec);
685
686 loop = wl_display_get_event_loop(ec->base.wl_display);
687 ec->drm_source =
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400688 wl_event_loop_add_fd(loop, ec->base.drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400689 WL_EVENT_READABLE, on_drm_input, ec);
690 setup_tty(ec, loop);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -0500691 ec->base.destroy = drm_destroy;
Kristian Høgsberg640609a2010-08-09 22:11:47 -0400692 ec->base.authenticate = drm_authenticate;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400693 ec->base.present = drm_compositor_present;
Kristian Høgsberg86e09892010-07-07 09:51:11 -0400694 ec->base.focus = 1;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400695
696 return &ec->base;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400697}