blob: f9f03bc8b3776687f63d32bd9b59f913b73f532d [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 Marchesinae37e6c2014-08-08 18:19:40 -070026
David Sodmanbbcb0522014-09-19 10:34:07 -070027#define FLAG_CLEAR 'c'
28#define FLAG_DAEMON 'd'
Dominik Behrd2530902016-05-05 14:01:06 -070029#define FLAG_ENABLE_GFX 'G'
Dominik Behr46c567f2016-03-08 15:11:48 -080030#define FLAG_ENABLE_VTS 'e'
David Sodmanbbcb0522014-09-19 10:34:07 -070031#define FLAG_FRAME_INTERVAL 'f'
32#define FLAG_GAMMA 'g'
Dominik Behr32a7c892015-10-09 15:47:53 -070033#define FLAG_IMAGE 'i'
34#define FLAG_IMAGE_HIRES 'I'
Dominik Behrfd9fdda2016-03-28 17:16:45 -070035#define FLAG_LOOP_COUNT 'C'
David Sodman8ef20062015-01-06 09:23:40 -080036#define FLAG_LOOP_START 'l'
37#define FLAG_LOOP_INTERVAL 'L'
38#define FLAG_LOOP_OFFSET 'o'
Dominik Behr222936d2016-05-05 13:50:50 -070039#define FLAG_NO_LOGIN 'n'
David Sodman8ef20062015-01-06 09:23:40 -080040#define FLAG_OFFSET 'O'
David Sodmanbbcb0522014-09-19 10:34:07 -070041#define FLAG_PRINT_RESOLUTION 'p'
Dominik Behr92d9e312016-05-04 20:10:48 -070042#define FLAG_SCALE 'S'
Dominik Behrfd9fdda2016-03-28 17:16:45 -070043#define FLAG_SPLASH_ONLY 's'
David Sodmanbbcb0522014-09-19 10:34:07 -070044
45static struct option command_options[] = {
46 { "clear", required_argument, NULL, FLAG_CLEAR },
47 { "daemon", no_argument, NULL, FLAG_DAEMON },
Dominik Behr46c567f2016-03-08 15:11:48 -080048 { "dev-mode", no_argument, NULL, FLAG_ENABLE_VTS },
Dominik Behrd2530902016-05-05 14:01:06 -070049 { "enable-gfx", no_argument, NULL, FLAG_ENABLE_GFX },
Dominik Behr46c567f2016-03-08 15:11:48 -080050 { "enable-vts", no_argument, NULL, FLAG_ENABLE_VTS },
David Sodmanbbcb0522014-09-19 10:34:07 -070051 { "frame-interval", required_argument, NULL, FLAG_FRAME_INTERVAL },
52 { "gamma", required_argument, NULL, FLAG_GAMMA },
Dominik Behr32a7c892015-10-09 15:47:53 -070053 { "image", required_argument, NULL, FLAG_IMAGE },
54 { "image-hires", required_argument, NULL, FLAG_IMAGE_HIRES },
Dominik Behrfd9fdda2016-03-28 17:16:45 -070055 { "loop-count", required_argument, NULL, FLAG_LOOP_COUNT },
David Sodman8ef20062015-01-06 09:23:40 -080056 { "loop-start", required_argument, NULL, FLAG_LOOP_START },
57 { "loop-interval", required_argument, NULL, FLAG_LOOP_INTERVAL },
58 { "loop-offset", required_argument, NULL, FLAG_LOOP_OFFSET },
Dominik Behr222936d2016-05-05 13:50:50 -070059 { "no-login", no_argument, NULL, FLAG_NO_LOGIN },
David Sodman8ef20062015-01-06 09:23:40 -080060 { "offset", required_argument, NULL, FLAG_OFFSET },
David Sodmanbbcb0522014-09-19 10:34:07 -070061 { "print-resolution", no_argument, NULL, FLAG_PRINT_RESOLUTION },
Dominik Behr92d9e312016-05-04 20:10:48 -070062 { "scale", required_argument, NULL, FLAG_SCALE },
Dominik Behrfd9fdda2016-03-28 17:16:45 -070063 { "splash-only", no_argument, NULL, FLAG_SPLASH_ONLY },
David Sodmanbbcb0522014-09-19 10:34:07 -070064 { NULL, 0, NULL, 0 }
65};
66
Dominik Behr46c567f2016-03-08 15:11:48 -080067commandflags_t command_flags = { 0 };
Dominik Behr580462b2014-11-20 13:50:05 -080068
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080069static void parse_offset(char* param, int32_t* x, int32_t* y)
David Sodman8ef20062015-01-06 09:23:40 -080070{
71 char* token;
72 char* saveptr;
73
74 token = strtok_r(param, ",", &saveptr);
75 if (token)
76 *x = strtol(token, NULL, 0);
77
78 token = strtok_r(NULL, ",", &saveptr);
79 if (token)
80 *y = strtol(token, NULL, 0);
81}
David Sodmanbbcb0522014-09-19 10:34:07 -070082
Dominik Behr44e07e62016-01-13 19:43:57 -080083int main_process_events(uint32_t usec)
84{
85 terminal_t* terminal;
86 terminal_t* new_terminal;
87 fd_set read_set, exception_set;
Dominik Behrd7112672016-01-20 16:59:34 -080088 int maxfd = -1;
Dominik Behr44e07e62016-01-13 19:43:57 -080089 int sstat;
90 struct timeval tm;
91 struct timeval* ptm;
92
93 terminal = term_get_current_terminal();
94
95 FD_ZERO(&read_set);
96 FD_ZERO(&exception_set);
97
Dominik Behrd7112672016-01-20 16:59:34 -080098 dbus_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behrd7112672016-01-20 16:59:34 -080099 input_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr5239cca2016-01-21 18:22:04 -0800100 dev_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -0800101
102 for (int i = 0; i < MAX_TERMINALS; i++) {
103 if (term_is_valid(term_get_terminal(i))) {
104 terminal_t* current_term = term_get_terminal(i);
Dominik Behrd7112672016-01-20 16:59:34 -0800105 term_add_fds(current_term, &read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -0800106 }
107 }
108
109 if (usec) {
110 ptm = &tm;
111 tm.tv_sec = 0;
112 tm.tv_usec = usec;
113 } else
114 ptm = NULL;
115
Dominik Behrd7112672016-01-20 16:59:34 -0800116 sstat = select(maxfd + 1, &read_set, NULL, &exception_set, ptm);
Dominik Behr44e07e62016-01-13 19:43:57 -0800117 if (sstat == 0)
118 return 0;
119
120 dbus_dispatch_io();
121
122 if (term_exception(terminal, &exception_set))
123 return -1;
124
Dominik Behr5239cca2016-01-21 18:22:04 -0800125 dev_dispatch_io(&read_set, &exception_set);
Dominik Behr44e07e62016-01-13 19:43:57 -0800126 input_dispatch_io(&read_set, &exception_set);
127
128 for (int i = 0; i < MAX_TERMINALS; i++) {
129 if (term_is_valid(term_get_terminal(i))) {
130 terminal_t* current_term = term_get_terminal(i);
131 term_dispatch_io(current_term, &read_set);
132 }
133 }
134
135 if (term_is_valid(terminal)) {
136 if (term_is_child_done(terminal)) {
137 if (terminal == term_get_terminal(SPLASH_TERMINAL)) {
138 /*
139 * Note: reference is not lost because it is still referenced
140 * by the splash_t structure which will ultimately destroy
Dominik Behrb1abcba2016-04-14 14:57:21 -0700141 * it, once it's safe to do so.
Dominik Behr44e07e62016-01-13 19:43:57 -0800142 */
143 term_set_terminal(SPLASH_TERMINAL, NULL);
144 return -1;
145 }
Dominik Behr83010f82016-03-18 18:43:08 -0700146 term_set_current_terminal(term_init(true));
Dominik Behr44e07e62016-01-13 19:43:57 -0800147 new_terminal = term_get_current_terminal();
148 if (!term_is_valid(new_terminal)) {
149 return -1;
150 }
151 term_activate(new_terminal);
152 term_close(terminal);
153 }
154 }
155
156 return 0;
157}
158
Dominik Behr46c567f2016-03-08 15:11:48 -0800159int main_loop(void)
Dominik Behr44e07e62016-01-13 19:43:57 -0800160{
Dominik Behr44e07e62016-01-13 19:43:57 -0800161 int status;
162
Dominik Behr44e07e62016-01-13 19:43:57 -0800163 while (1) {
164 status = main_process_events(0);
165 if (status != 0) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700166 LOG(ERROR, "Input process returned %d.", status);
Dominik Behr44e07e62016-01-13 19:43:57 -0800167 break;
168 }
169 }
170
171 return 0;
172}
173
Dominik Behr46c567f2016-03-08 15:11:48 -0800174bool set_drm_master_relax(void)
175{
176 int fd;
177 int num_written;
178
179 /*
180 * Setting drm_master_relax flag in kernel allows us to transfer DRM master
Dominik Behrb1abcba2016-04-14 14:57:21 -0700181 * between Chrome and frecon.
Dominik Behr46c567f2016-03-08 15:11:48 -0800182 */
183 fd = open("/sys/kernel/debug/dri/drm_master_relax", O_WRONLY);
184 if (fd != -1) {
185 num_written = write(fd, "Y", 1);
186 close(fd);
187 if (num_written != 1) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700188 LOG(ERROR, "Unable to set drm_master_relax.");
Dominik Behr46c567f2016-03-08 15:11:48 -0800189 return false;
190 }
191 } else {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700192 LOG(ERROR, "Unable to open drm_master_relax.");
Dominik Behr46c567f2016-03-08 15:11:48 -0800193 return false;
194 }
195 return true;
196}
197
198static void main_on_login_prompt_visible(void* ptr)
199{
200 if (command_flags.daemon && !command_flags.enable_vts) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700201 LOG(INFO, "Chrome started, our work is done, exiting.");
Dominik Behr46c567f2016-03-08 15:11:48 -0800202 exit(EXIT_SUCCESS);
203 } else
204 if (ptr) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700205 LOG(INFO, "Chrome started, splash screen is not needed anymore.");
Dominik Behr46c567f2016-03-08 15:11:48 -0800206 splash_destroy((splash_t*)ptr);
207 }
208}
Dominik Behr44e07e62016-01-13 19:43:57 -0800209
David Sodmanbbcb0522014-09-19 10:34:07 -0700210int main(int argc, char* argv[])
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700211{
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700212 int ret;
David Sodmanbbcb0522014-09-19 10:34:07 -0700213 int c;
David Sodman8ef20062015-01-06 09:23:40 -0800214 int32_t x, y;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800215 splash_t* splash;
Dominik Behrb1abcba2016-04-14 14:57:21 -0700216 drm_t* drm;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700217
Dominik Behr2b9f1232016-08-02 01:11:12 -0700218 fix_stdio();
219
Dominik Behrb1abcba2016-04-14 14:57:21 -0700220 /* Find out if we are going to be a daemon .*/
221 optind = 1;
222 for (;;) {
223 c = getopt_long(argc, argv, "", command_options, NULL);
224 if (c == -1) {
225 break;
226 } else if (c == FLAG_DAEMON) {
227 command_flags.daemon = true;
228 }
229 }
230
231 /* Handle resolution special before splash init. */
232 optind = 1;
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700233 for (;;) {
234 c = getopt_long(argc, argv, "", command_options, NULL);
235 if (c == -1) {
236 break;
237 } else if (c == FLAG_PRINT_RESOLUTION) {
Dominik Behr83010f82016-03-18 18:43:08 -0700238 drm_t *drm = drm_scan();
239 if (!drm)
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700240 return EXIT_FAILURE;
241
Dominik Behr83010f82016-03-18 18:43:08 -0700242 printf("%d %d", drm_gethres(drm),
243 drm_getvres(drm));
244 drm_delref(drm);
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700245 return EXIT_SUCCESS;
246 }
247 }
248
Dominik Behrb1abcba2016-04-14 14:57:21 -0700249 splash = splash_init();
250 if (splash == NULL) {
251 LOG(ERROR, "Splash init failed.");
252 return EXIT_FAILURE;
253 }
254
255 if (command_flags.daemon) {
256 splash_present_term_file(splash);
257 daemonize();
258 }
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700259
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700260 ret = input_init();
261 if (ret) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700262 LOG(ERROR, "Input init failed.");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700263 return EXIT_FAILURE;
264 }
265
Dominik Behr5239cca2016-01-21 18:22:04 -0800266 ret = dev_init();
267 if (ret) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700268 LOG(ERROR, "Device management init failed.");
Dominik Behr5239cca2016-01-21 18:22:04 -0800269 return EXIT_FAILURE;
270 }
271
Dominik Behrb1abcba2016-04-14 14:57:21 -0700272 drm_set(drm = drm_scan());
273 /* Update DRM object in splash term and set video mode. */
274 splash_redrm(splash);
David Sodmanbbcb0522014-09-19 10:34:07 -0700275
Dominik Behrb1abcba2016-04-14 14:57:21 -0700276 optind = 1;
David Sodmanbbcb0522014-09-19 10:34:07 -0700277 for (;;) {
278 c = getopt_long(argc, argv, "", command_options, NULL);
279
280 if (c == -1)
281 break;
282
283 switch (c) {
284 case FLAG_CLEAR:
285 splash_set_clear(splash, strtoul(optarg, NULL, 0));
286 break;
287
David Sodman8ef20062015-01-06 09:23:40 -0800288 case FLAG_FRAME_INTERVAL:
289 splash_set_default_duration(splash, strtoul(optarg, NULL, 0));
290 break;
291
Dominik Behrd2530902016-05-05 14:01:06 -0700292 case FLAG_ENABLE_GFX:
293 command_flags.enable_gfx = true;
294 break;
295
Dominik Behr46c567f2016-03-08 15:11:48 -0800296 case FLAG_ENABLE_VTS:
297 command_flags.enable_vts = true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700298 break;
299
Dominik Behr32a7c892015-10-09 15:47:53 -0700300 case FLAG_IMAGE:
301 if (!splash_is_hires(splash))
302 splash_add_image(splash, optarg);
303 break;
304
305 case FLAG_IMAGE_HIRES:
306 if (splash_is_hires(splash))
307 splash_add_image(splash, optarg);
308 break;
309
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700310 case FLAG_LOOP_COUNT:
311 splash_set_loop_count(splash, strtoul(optarg, NULL, 0));
312 break;
313
David Sodman8ef20062015-01-06 09:23:40 -0800314 case FLAG_LOOP_START:
315 splash_set_loop_start(splash, strtoul(optarg, NULL, 0));
316 break;
317
318 case FLAG_LOOP_INTERVAL:
319 splash_set_loop_duration(splash, strtoul(optarg, NULL, 0));
320 break;
321
322 case FLAG_LOOP_OFFSET:
323 parse_offset(optarg, &x, &y);
324 splash_set_loop_offset(splash, x, y);
325 break;
326
Dominik Behr222936d2016-05-05 13:50:50 -0700327 case FLAG_NO_LOGIN:
328 command_flags.no_login = true;
329 break;
330
David Sodman8ef20062015-01-06 09:23:40 -0800331 case FLAG_OFFSET:
332 parse_offset(optarg, &x, &y);
333 splash_set_offset(splash, x, y);
334 break;
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700335
Dominik Behr92d9e312016-05-04 20:10:48 -0700336 case FLAG_SCALE:
337 splash_set_scale(splash, strtoul(optarg, NULL, 0));
338 break;
339
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700340 case FLAG_SPLASH_ONLY:
341 command_flags.splash_only = true;
342 break;
David Sodmanbbcb0522014-09-19 10:34:07 -0700343 }
344 }
345
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800346 for (int i = optind; i < argc; i++)
David Sodman8ef20062015-01-06 09:23:40 -0800347 splash_add_image(splash, argv[i]);
348
David Sodmanf0a925a2015-05-04 11:19:19 -0700349 if (splash_num_images(splash) > 0) {
Dominik Behr797a3832016-01-11 15:53:11 -0800350 ret = splash_run(splash);
David Sodmanbbcb0522014-09-19 10:34:07 -0700351 if (ret) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700352 LOG(ERROR, "Splash_run failed: %d.", ret);
Yuly Novikov945871e2015-05-23 00:00:41 -0400353 return EXIT_FAILURE;
David Sodmanbbcb0522014-09-19 10:34:07 -0700354 }
355 }
356
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700357 if (command_flags.splash_only)
358 goto main_done;
359
David Sodmanbbcb0522014-09-19 10:34:07 -0700360 /*
Dominik Behr46c567f2016-03-08 15:11:48 -0800361 * The DBUS service launches later than the boot-splash service, and
362 * as a result, when splash_run starts DBUS is not yet up, but, by
363 * the time splash_run completes, it is running.
Dominik Behrb1abcba2016-04-14 14:57:21 -0700364 * We really need DBUS now, so we can interact with Chrome.
David Sodmanbbcb0522014-09-19 10:34:07 -0700365 */
Dominik Behr5f6742f2016-03-10 18:03:54 -0800366 dbus_init_wait();
David Sodman8ef20062015-01-06 09:23:40 -0800367
Dominik Behr46c567f2016-03-08 15:11:48 -0800368 /*
369 * Ask DBUS to call us back so we can destroy splash (or quit) when login
Dominik Behrb1abcba2016-04-14 14:57:21 -0700370 * prompt is visible.
Dominik Behr46c567f2016-03-08 15:11:48 -0800371 */
372 dbus_set_login_prompt_visible_callback(main_on_login_prompt_visible,
373 (void*)splash);
374
Dominik Behr1883c042016-04-27 12:31:02 -0700375 /*
376 * Ask DBUS to notify us when suspend has finished so monitors can be reprobed
377 * in case they changed during suspend.
378 */
379 dbus_set_suspend_done_callback(term_suspend_done, NULL);
380
Dominik Behr46c567f2016-03-08 15:11:48 -0800381 if (command_flags.daemon) {
382 if (command_flags.enable_vts)
Dominik Behr83864df2016-04-21 12:35:08 -0700383 set_drm_master_relax(); /* TODO(dbehr) Remove when Chrome is fixed to actually release master. */
Dominik Behr83864df2016-04-21 12:35:08 -0700384 term_background();
Dominik Behr46c567f2016-03-08 15:11:48 -0800385 } else {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700386 /* Create and switch to first term in interactve mode. */
Dominik Behr46c567f2016-03-08 15:11:48 -0800387 terminal_t* terminal;
Dominik Behr83864df2016-04-21 12:35:08 -0700388 set_drm_master_relax(); /* TODO(dbehr) Remove when Chrome is fixed to actually release master. */
389 term_foreground();
Dominik Behr83010f82016-03-18 18:43:08 -0700390 term_set_current_terminal(term_init(true));
Dominik Behr46c567f2016-03-08 15:11:48 -0800391 terminal = term_get_current_terminal();
392 term_activate(terminal);
393 }
394
395 ret = main_loop();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700396
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700397main_done:
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700398 input_close();
Dominik Behr5239cca2016-01-21 18:22:04 -0800399 dev_close();
Dominik Behr44e07e62016-01-13 19:43:57 -0800400 dbus_destroy();
Dominik Behr83010f82016-03-18 18:43:08 -0700401 drm_close();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700402
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700403 return ret;
404}