blob: 33f404078a099ceaf78338ce5d8144b7d880c220 [file] [log] [blame]
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07001/*
David Sodman8ef20062015-01-06 09:23:40 -08002 * Copyright 2014 The Chromium OS Authors. All rights reserved.
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07003 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Dominik Behr46c567f2016-03-08 15:11:48 -08007#include <fcntl.h>
Dominik Behr580462b2014-11-20 13:50:05 -08008#include <getopt.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07009#include <libtsm.h>
Dominik Behr580462b2014-11-20 13:50:05 -080010#include <memory.h>
11#include <stdbool.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070012#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
Dominik Behr46c567f2016-03-08 15:11:48 -080015#include <sys/stat.h>
16#include <sys/types.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070017
Dominik Behr580462b2014-11-20 13:50:05 -080018#include "dbus.h"
Dominik Behr44e07e62016-01-13 19:43:57 -080019#include "dbus_interface.h"
Dominik Behr5239cca2016-01-21 18:22:04 -080020#include "dev.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070021#include "input.h"
Dominik Behr44e07e62016-01-13 19:43:57 -080022#include "main.h"
Dominik Behr580462b2014-11-20 13:50:05 -080023#include "splash.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070024#include "term.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070025#include "util.h"
Stéphane Marchesin62561a12015-12-11 17:32:37 -080026#include "video.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070027
Dominik Behr46c567f2016-03-08 15:11:48 -080028#define DBUS_WAIT_DELAY_US (50000)
29
David Sodmanbbcb0522014-09-19 10:34:07 -070030#define FLAG_CLEAR 'c'
31#define FLAG_DAEMON 'd'
Dominik Behr46c567f2016-03-08 15:11:48 -080032#define FLAG_ENABLE_VTS 'e'
David Sodmanbbcb0522014-09-19 10:34:07 -070033#define FLAG_FRAME_INTERVAL 'f'
34#define FLAG_GAMMA 'g'
Dominik Behr32a7c892015-10-09 15:47:53 -070035#define FLAG_IMAGE 'i'
36#define FLAG_IMAGE_HIRES 'I'
David Sodman8ef20062015-01-06 09:23:40 -080037#define FLAG_LOOP_START 'l'
38#define FLAG_LOOP_INTERVAL 'L'
39#define FLAG_LOOP_OFFSET 'o'
40#define FLAG_OFFSET 'O'
David Sodmanbbcb0522014-09-19 10:34:07 -070041#define FLAG_PRINT_RESOLUTION 'p'
42
43static struct option command_options[] = {
44 { "clear", required_argument, NULL, FLAG_CLEAR },
45 { "daemon", no_argument, NULL, FLAG_DAEMON },
Dominik Behr46c567f2016-03-08 15:11:48 -080046 { "dev-mode", no_argument, NULL, FLAG_ENABLE_VTS },
47 { "enable-vts", no_argument, NULL, FLAG_ENABLE_VTS },
David Sodmanbbcb0522014-09-19 10:34:07 -070048 { "frame-interval", required_argument, NULL, FLAG_FRAME_INTERVAL },
49 { "gamma", required_argument, NULL, FLAG_GAMMA },
Dominik Behr32a7c892015-10-09 15:47:53 -070050 { "image", required_argument, NULL, FLAG_IMAGE },
51 { "image-hires", required_argument, NULL, FLAG_IMAGE_HIRES },
David Sodman8ef20062015-01-06 09:23:40 -080052 { "loop-start", required_argument, NULL, FLAG_LOOP_START },
53 { "loop-interval", required_argument, NULL, FLAG_LOOP_INTERVAL },
54 { "loop-offset", required_argument, NULL, FLAG_LOOP_OFFSET },
55 { "offset", required_argument, NULL, FLAG_OFFSET },
David Sodmanbbcb0522014-09-19 10:34:07 -070056 { "print-resolution", no_argument, NULL, FLAG_PRINT_RESOLUTION },
57 { NULL, 0, NULL, 0 }
58};
59
Dominik Behr46c567f2016-03-08 15:11:48 -080060commandflags_t command_flags = { 0 };
Dominik Behr580462b2014-11-20 13:50:05 -080061
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080062static void parse_offset(char* param, int32_t* x, int32_t* y)
David Sodman8ef20062015-01-06 09:23:40 -080063{
64 char* token;
65 char* saveptr;
66
67 token = strtok_r(param, ",", &saveptr);
68 if (token)
69 *x = strtol(token, NULL, 0);
70
71 token = strtok_r(NULL, ",", &saveptr);
72 if (token)
73 *y = strtol(token, NULL, 0);
74}
David Sodmanbbcb0522014-09-19 10:34:07 -070075
Dominik Behr44e07e62016-01-13 19:43:57 -080076int main_process_events(uint32_t usec)
77{
78 terminal_t* terminal;
79 terminal_t* new_terminal;
80 fd_set read_set, exception_set;
Dominik Behrd7112672016-01-20 16:59:34 -080081 int maxfd = -1;
Dominik Behr44e07e62016-01-13 19:43:57 -080082 int sstat;
83 struct timeval tm;
84 struct timeval* ptm;
85
86 terminal = term_get_current_terminal();
87
88 FD_ZERO(&read_set);
89 FD_ZERO(&exception_set);
90
Dominik Behrd7112672016-01-20 16:59:34 -080091 dbus_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behrd7112672016-01-20 16:59:34 -080092 input_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr5239cca2016-01-21 18:22:04 -080093 dev_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -080094
95 for (int i = 0; i < MAX_TERMINALS; i++) {
96 if (term_is_valid(term_get_terminal(i))) {
97 terminal_t* current_term = term_get_terminal(i);
Dominik Behrd7112672016-01-20 16:59:34 -080098 term_add_fds(current_term, &read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -080099 }
100 }
101
102 if (usec) {
103 ptm = &tm;
104 tm.tv_sec = 0;
105 tm.tv_usec = usec;
106 } else
107 ptm = NULL;
108
Dominik Behrd7112672016-01-20 16:59:34 -0800109 sstat = select(maxfd + 1, &read_set, NULL, &exception_set, ptm);
Dominik Behr44e07e62016-01-13 19:43:57 -0800110 if (sstat == 0)
111 return 0;
112
113 dbus_dispatch_io();
114
115 if (term_exception(terminal, &exception_set))
116 return -1;
117
Dominik Behr5239cca2016-01-21 18:22:04 -0800118 dev_dispatch_io(&read_set, &exception_set);
Dominik Behr44e07e62016-01-13 19:43:57 -0800119 input_dispatch_io(&read_set, &exception_set);
120
121 for (int i = 0; i < MAX_TERMINALS; i++) {
122 if (term_is_valid(term_get_terminal(i))) {
123 terminal_t* current_term = term_get_terminal(i);
124 term_dispatch_io(current_term, &read_set);
125 }
126 }
127
128 if (term_is_valid(terminal)) {
129 if (term_is_child_done(terminal)) {
130 if (terminal == term_get_terminal(SPLASH_TERMINAL)) {
131 /*
132 * Note: reference is not lost because it is still referenced
133 * by the splash_t structure which will ultimately destroy
134 * it, once it's safe to do so
135 */
136 term_set_terminal(SPLASH_TERMINAL, NULL);
137 return -1;
138 }
139 term_set_current_terminal(term_init(true, term_getvideo(terminal)));
140 new_terminal = term_get_current_terminal();
141 if (!term_is_valid(new_terminal)) {
142 return -1;
143 }
144 term_activate(new_terminal);
145 term_close(terminal);
146 }
147 }
148
149 return 0;
150}
151
Dominik Behr46c567f2016-03-08 15:11:48 -0800152int main_loop(void)
Dominik Behr44e07e62016-01-13 19:43:57 -0800153{
Dominik Behr44e07e62016-01-13 19:43:57 -0800154 int status;
155
Dominik Behr44e07e62016-01-13 19:43:57 -0800156 while (1) {
157 status = main_process_events(0);
158 if (status != 0) {
159 LOG(ERROR, "input process returned %d", status);
160 break;
161 }
162 }
163
164 return 0;
165}
166
Dominik Behr46c567f2016-03-08 15:11:48 -0800167bool set_drm_master_relax(void)
168{
169 int fd;
170 int num_written;
171
172 /*
173 * Setting drm_master_relax flag in kernel allows us to transfer DRM master
174 * between Chrome and frecon
175 */
176 fd = open("/sys/kernel/debug/dri/drm_master_relax", O_WRONLY);
177 if (fd != -1) {
178 num_written = write(fd, "Y", 1);
179 close(fd);
180 if (num_written != 1) {
181 LOG(ERROR, "Unable to set drm_master_relax");
182 return false;
183 }
184 } else {
185 LOG(ERROR, "unable to open drm_master_relax");
186 return false;
187 }
188 return true;
189}
190
191static void main_on_login_prompt_visible(void* ptr)
192{
193 if (command_flags.daemon && !command_flags.enable_vts) {
194 exit(EXIT_SUCCESS);
195 } else
196 if (ptr) {
197 splash_destroy((splash_t*)ptr);
198 }
199}
Dominik Behr44e07e62016-01-13 19:43:57 -0800200
David Sodmanbbcb0522014-09-19 10:34:07 -0700201int main(int argc, char* argv[])
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700202{
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700203 int ret;
David Sodmanbbcb0522014-09-19 10:34:07 -0700204 int c;
David Sodman8ef20062015-01-06 09:23:40 -0800205 int32_t x, y;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800206 splash_t* splash;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700207
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700208 /* Handle resolution special before splash init */
209 for (;;) {
210 c = getopt_long(argc, argv, "", command_options, NULL);
211 if (c == -1) {
212 break;
213 } else if (c == FLAG_PRINT_RESOLUTION) {
214 video_t *video = video_init();
215 if (!video)
216 return EXIT_FAILURE;
217
218 printf("%d %d", video_getwidth(video),
219 video_getheight(video));
220 video_close(video);
221 return EXIT_SUCCESS;
222 }
223 }
224
225 /* Reset option parsing */
226 optind = 1;
227
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700228 ret = input_init();
229 if (ret) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700230 LOG(ERROR, "Input init failed");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700231 return EXIT_FAILURE;
232 }
233
Dominik Behr5239cca2016-01-21 18:22:04 -0800234 ret = dev_init();
235 if (ret) {
236 LOG(ERROR, "Device management init failed");
237 return EXIT_FAILURE;
238 }
239
David Sodmanbf3f2842014-11-12 08:26:58 -0800240 splash = splash_init();
David Sodmanbbcb0522014-09-19 10:34:07 -0700241 if (splash == NULL) {
242 LOG(ERROR, "splash init failed");
243 return EXIT_FAILURE;
244 }
245
246 for (;;) {
247 c = getopt_long(argc, argv, "", command_options, NULL);
248
249 if (c == -1)
250 break;
251
252 switch (c) {
253 case FLAG_CLEAR:
254 splash_set_clear(splash, strtoul(optarg, NULL, 0));
255 break;
256
257 case FLAG_DAEMON:
Dominik Behr46c567f2016-03-08 15:11:48 -0800258 command_flags.daemon = true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700259 break;
260
David Sodman8ef20062015-01-06 09:23:40 -0800261 case FLAG_FRAME_INTERVAL:
262 splash_set_default_duration(splash, strtoul(optarg, NULL, 0));
263 break;
264
Dominik Behr46c567f2016-03-08 15:11:48 -0800265 case FLAG_ENABLE_VTS:
266 command_flags.enable_vts = true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700267 break;
268
Dominik Behr32a7c892015-10-09 15:47:53 -0700269 case FLAG_IMAGE:
270 if (!splash_is_hires(splash))
271 splash_add_image(splash, optarg);
272 break;
273
274 case FLAG_IMAGE_HIRES:
275 if (splash_is_hires(splash))
276 splash_add_image(splash, optarg);
277 break;
278
David Sodman8ef20062015-01-06 09:23:40 -0800279 case FLAG_LOOP_START:
280 splash_set_loop_start(splash, strtoul(optarg, NULL, 0));
281 break;
282
283 case FLAG_LOOP_INTERVAL:
284 splash_set_loop_duration(splash, strtoul(optarg, NULL, 0));
285 break;
286
287 case FLAG_LOOP_OFFSET:
288 parse_offset(optarg, &x, &y);
289 splash_set_loop_offset(splash, x, y);
290 break;
291
292 case FLAG_OFFSET:
293 parse_offset(optarg, &x, &y);
294 splash_set_offset(splash, x, y);
295 break;
David Sodmanbbcb0522014-09-19 10:34:07 -0700296 }
297 }
298
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800299 for (int i = optind; i < argc; i++)
David Sodman8ef20062015-01-06 09:23:40 -0800300 splash_add_image(splash, argv[i]);
301
Dominik Behr46c567f2016-03-08 15:11:48 -0800302 if (command_flags.daemon) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700303 splash_present_term_file(splash);
304 daemonize();
305 }
Dominik Behr46c567f2016-03-08 15:11:48 -0800306
David Sodmanf0a925a2015-05-04 11:19:19 -0700307 if (splash_num_images(splash) > 0) {
Dominik Behr797a3832016-01-11 15:53:11 -0800308 ret = splash_run(splash);
David Sodmanbbcb0522014-09-19 10:34:07 -0700309 if (ret) {
Yuly Novikov945871e2015-05-23 00:00:41 -0400310 LOG(ERROR, "splash_run failed: %d", ret);
311 return EXIT_FAILURE;
David Sodmanbbcb0522014-09-19 10:34:07 -0700312 }
313 }
314
315 /*
Dominik Behr46c567f2016-03-08 15:11:48 -0800316 * The DBUS service launches later than the boot-splash service, and
317 * as a result, when splash_run starts DBUS is not yet up, but, by
318 * the time splash_run completes, it is running.
319 * We really need DBUS now, so we can interact with Chrome
David Sodmanbbcb0522014-09-19 10:34:07 -0700320 */
Dominik Behr46c567f2016-03-08 15:11:48 -0800321 while (!dbus_is_initialized()) {
Dominik Behr797a3832016-01-11 15:53:11 -0800322 dbus_init();
Dominik Behr46c567f2016-03-08 15:11:48 -0800323 usleep(DBUS_WAIT_DELAY_US);
David Sodmanbbcb0522014-09-19 10:34:07 -0700324 }
David Sodman8ef20062015-01-06 09:23:40 -0800325
Dominik Behr46c567f2016-03-08 15:11:48 -0800326 /*
327 * Ask DBUS to call us back so we can destroy splash (or quit) when login
328 * prompt is visible;
329 */
330 dbus_set_login_prompt_visible_callback(main_on_login_prompt_visible,
331 (void*)splash);
332
333 if (command_flags.daemon) {
334 if (command_flags.enable_vts)
335 set_drm_master_relax();
336 dbus_take_display_ownership();
337 } else {
338 set_drm_master_relax();
339 dbus_release_display_ownership();
340 /* create and switch to first term in interactve mode */
341 terminal_t* terminal;
342 dbus_release_display_ownership();
343 term_set_current_terminal(term_init(true, NULL));
344 terminal = term_get_current_terminal();
345 term_activate(terminal);
346 }
347
348 ret = main_loop();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700349
350 input_close();
Dominik Behr5239cca2016-01-21 18:22:04 -0800351 dev_close();
Dominik Behr44e07e62016-01-13 19:43:57 -0800352 dbus_destroy();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700353
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700354 return ret;
355}