blob: 21c8908855cdbaef31e0c5b310097d2720bc924f [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 Behr0bb51772016-07-26 18:04:53 -070030#define FLAG_ENABLE_VT1 '1'
Dominik Behr46c567f2016-03-08 15:11:48 -080031#define FLAG_ENABLE_VTS 'e'
David Sodmanbbcb0522014-09-19 10:34:07 -070032#define FLAG_FRAME_INTERVAL 'f'
33#define FLAG_GAMMA 'g'
Dominik Behr32a7c892015-10-09 15:47:53 -070034#define FLAG_IMAGE 'i'
35#define FLAG_IMAGE_HIRES 'I'
Dominik Behrfd9fdda2016-03-28 17:16:45 -070036#define FLAG_LOOP_COUNT 'C'
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'
Dominik Behr222936d2016-05-05 13:50:50 -070040#define FLAG_NO_LOGIN 'n'
David Sodman8ef20062015-01-06 09:23:40 -080041#define FLAG_OFFSET 'O'
David Sodmanbbcb0522014-09-19 10:34:07 -070042#define FLAG_PRINT_RESOLUTION 'p'
Dominik Behr92d9e312016-05-04 20:10:48 -070043#define FLAG_SCALE 'S'
Dominik Behrfd9fdda2016-03-28 17:16:45 -070044#define FLAG_SPLASH_ONLY 's'
David Sodmanbbcb0522014-09-19 10:34:07 -070045
46static struct option command_options[] = {
47 { "clear", required_argument, NULL, FLAG_CLEAR },
48 { "daemon", no_argument, NULL, FLAG_DAEMON },
Dominik Behr46c567f2016-03-08 15:11:48 -080049 { "dev-mode", no_argument, NULL, FLAG_ENABLE_VTS },
Dominik Behrd2530902016-05-05 14:01:06 -070050 { "enable-gfx", no_argument, NULL, FLAG_ENABLE_GFX },
Dominik Behr0bb51772016-07-26 18:04:53 -070051 { "enable-vt1", no_argument, NULL, FLAG_ENABLE_VT1 },
Dominik Behr46c567f2016-03-08 15:11:48 -080052 { "enable-vts", no_argument, NULL, FLAG_ENABLE_VTS },
David Sodmanbbcb0522014-09-19 10:34:07 -070053 { "frame-interval", required_argument, NULL, FLAG_FRAME_INTERVAL },
54 { "gamma", required_argument, NULL, FLAG_GAMMA },
Dominik Behr32a7c892015-10-09 15:47:53 -070055 { "image", required_argument, NULL, FLAG_IMAGE },
56 { "image-hires", required_argument, NULL, FLAG_IMAGE_HIRES },
Dominik Behrfd9fdda2016-03-28 17:16:45 -070057 { "loop-count", required_argument, NULL, FLAG_LOOP_COUNT },
David Sodman8ef20062015-01-06 09:23:40 -080058 { "loop-start", required_argument, NULL, FLAG_LOOP_START },
59 { "loop-interval", required_argument, NULL, FLAG_LOOP_INTERVAL },
60 { "loop-offset", required_argument, NULL, FLAG_LOOP_OFFSET },
Dominik Behr222936d2016-05-05 13:50:50 -070061 { "no-login", no_argument, NULL, FLAG_NO_LOGIN },
David Sodman8ef20062015-01-06 09:23:40 -080062 { "offset", required_argument, NULL, FLAG_OFFSET },
David Sodmanbbcb0522014-09-19 10:34:07 -070063 { "print-resolution", no_argument, NULL, FLAG_PRINT_RESOLUTION },
Dominik Behr92d9e312016-05-04 20:10:48 -070064 { "scale", required_argument, NULL, FLAG_SCALE },
Dominik Behrfd9fdda2016-03-28 17:16:45 -070065 { "splash-only", no_argument, NULL, FLAG_SPLASH_ONLY },
David Sodmanbbcb0522014-09-19 10:34:07 -070066 { NULL, 0, NULL, 0 }
67};
68
Dominik Behr46c567f2016-03-08 15:11:48 -080069commandflags_t command_flags = { 0 };
Dominik Behr580462b2014-11-20 13:50:05 -080070
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080071static void parse_offset(char* param, int32_t* x, int32_t* y)
David Sodman8ef20062015-01-06 09:23:40 -080072{
73 char* token;
74 char* saveptr;
75
76 token = strtok_r(param, ",", &saveptr);
77 if (token)
78 *x = strtol(token, NULL, 0);
79
80 token = strtok_r(NULL, ",", &saveptr);
81 if (token)
82 *y = strtol(token, NULL, 0);
83}
David Sodmanbbcb0522014-09-19 10:34:07 -070084
Dominik Behr44e07e62016-01-13 19:43:57 -080085int main_process_events(uint32_t usec)
86{
87 terminal_t* terminal;
88 terminal_t* new_terminal;
89 fd_set read_set, exception_set;
Dominik Behrd7112672016-01-20 16:59:34 -080090 int maxfd = -1;
Dominik Behr44e07e62016-01-13 19:43:57 -080091 int sstat;
92 struct timeval tm;
93 struct timeval* ptm;
94
95 terminal = term_get_current_terminal();
96
97 FD_ZERO(&read_set);
98 FD_ZERO(&exception_set);
99
Dominik Behrd7112672016-01-20 16:59:34 -0800100 dbus_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behrd7112672016-01-20 16:59:34 -0800101 input_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr5239cca2016-01-21 18:22:04 -0800102 dev_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -0800103
104 for (int i = 0; i < MAX_TERMINALS; i++) {
105 if (term_is_valid(term_get_terminal(i))) {
106 terminal_t* current_term = term_get_terminal(i);
Dominik Behrd7112672016-01-20 16:59:34 -0800107 term_add_fds(current_term, &read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -0800108 }
109 }
110
111 if (usec) {
112 ptm = &tm;
113 tm.tv_sec = 0;
114 tm.tv_usec = usec;
115 } else
116 ptm = NULL;
117
Dominik Behrd7112672016-01-20 16:59:34 -0800118 sstat = select(maxfd + 1, &read_set, NULL, &exception_set, ptm);
Dominik Behr44e07e62016-01-13 19:43:57 -0800119 if (sstat == 0)
120 return 0;
121
122 dbus_dispatch_io();
123
124 if (term_exception(terminal, &exception_set))
125 return -1;
126
Dominik Behr5239cca2016-01-21 18:22:04 -0800127 dev_dispatch_io(&read_set, &exception_set);
Dominik Behr44e07e62016-01-13 19:43:57 -0800128 input_dispatch_io(&read_set, &exception_set);
129
130 for (int i = 0; i < MAX_TERMINALS; i++) {
131 if (term_is_valid(term_get_terminal(i))) {
132 terminal_t* current_term = term_get_terminal(i);
133 term_dispatch_io(current_term, &read_set);
134 }
135 }
136
137 if (term_is_valid(terminal)) {
138 if (term_is_child_done(terminal)) {
Dominik Behr0bb51772016-07-26 18:04:53 -0700139 if (terminal == term_get_terminal(SPLASH_TERMINAL) && !command_flags.enable_vt1) {
Dominik Behr44e07e62016-01-13 19:43:57 -0800140 /*
141 * Note: reference is not lost because it is still referenced
142 * by the splash_t structure which will ultimately destroy
Dominik Behrb1abcba2016-04-14 14:57:21 -0700143 * it, once it's safe to do so.
Dominik Behr44e07e62016-01-13 19:43:57 -0800144 */
145 term_set_terminal(SPLASH_TERMINAL, NULL);
146 return -1;
147 }
Dominik Behr83010f82016-03-18 18:43:08 -0700148 term_set_current_terminal(term_init(true));
Dominik Behr44e07e62016-01-13 19:43:57 -0800149 new_terminal = term_get_current_terminal();
150 if (!term_is_valid(new_terminal)) {
151 return -1;
152 }
153 term_activate(new_terminal);
154 term_close(terminal);
155 }
156 }
157
158 return 0;
159}
160
Dominik Behr46c567f2016-03-08 15:11:48 -0800161int main_loop(void)
Dominik Behr44e07e62016-01-13 19:43:57 -0800162{
Dominik Behr44e07e62016-01-13 19:43:57 -0800163 int status;
164
Dominik Behr44e07e62016-01-13 19:43:57 -0800165 while (1) {
166 status = main_process_events(0);
167 if (status != 0) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700168 LOG(ERROR, "Input process returned %d.", status);
Dominik Behr44e07e62016-01-13 19:43:57 -0800169 break;
170 }
171 }
172
173 return 0;
174}
175
Dominik Behr46c567f2016-03-08 15:11:48 -0800176bool set_drm_master_relax(void)
177{
178 int fd;
179 int num_written;
180
181 /*
182 * Setting drm_master_relax flag in kernel allows us to transfer DRM master
Dominik Behrb1abcba2016-04-14 14:57:21 -0700183 * between Chrome and frecon.
Dominik Behr46c567f2016-03-08 15:11:48 -0800184 */
185 fd = open("/sys/kernel/debug/dri/drm_master_relax", O_WRONLY);
186 if (fd != -1) {
187 num_written = write(fd, "Y", 1);
188 close(fd);
189 if (num_written != 1) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700190 LOG(ERROR, "Unable to set drm_master_relax.");
Dominik Behr46c567f2016-03-08 15:11:48 -0800191 return false;
192 }
193 } else {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700194 LOG(ERROR, "Unable to open drm_master_relax.");
Dominik Behr46c567f2016-03-08 15:11:48 -0800195 return false;
196 }
197 return true;
198}
199
200static void main_on_login_prompt_visible(void* ptr)
201{
202 if (command_flags.daemon && !command_flags.enable_vts) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700203 LOG(INFO, "Chrome started, our work is done, exiting.");
Dominik Behr46c567f2016-03-08 15:11:48 -0800204 exit(EXIT_SUCCESS);
205 } else
206 if (ptr) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700207 LOG(INFO, "Chrome started, splash screen is not needed anymore.");
Dominik Behr0bb51772016-07-26 18:04:53 -0700208 if (command_flags.enable_vt1)
209 LOG(WARNING, "VT1 enabled and Chrome is active!");
210 splash_destroy((splash_t*)ptr, false);
Dominik Behr46c567f2016-03-08 15:11:48 -0800211 }
212}
Dominik Behr44e07e62016-01-13 19:43:57 -0800213
David Sodmanbbcb0522014-09-19 10:34:07 -0700214int main(int argc, char* argv[])
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700215{
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700216 int ret;
David Sodmanbbcb0522014-09-19 10:34:07 -0700217 int c;
David Sodman8ef20062015-01-06 09:23:40 -0800218 int32_t x, y;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800219 splash_t* splash;
Dominik Behrb1abcba2016-04-14 14:57:21 -0700220 drm_t* drm;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700221
Dominik Behr2b9f1232016-08-02 01:11:12 -0700222 fix_stdio();
223
Dominik Behrb1abcba2016-04-14 14:57:21 -0700224 optind = 1;
225 for (;;) {
226 c = getopt_long(argc, argv, "", command_options, NULL);
Dominik Behr0bb51772016-07-26 18:04:53 -0700227
228 if (c == -1)
Dominik Behrb1abcba2016-04-14 14:57:21 -0700229 break;
Dominik Behr0bb51772016-07-26 18:04:53 -0700230
231 switch (c) {
232 case FLAG_DAEMON:
233 command_flags.daemon = true;
234 break;
235
236 case FLAG_ENABLE_GFX:
237 command_flags.enable_gfx = true;
238 break;
239
240 case FLAG_ENABLE_VT1:
241 command_flags.enable_vt1 = true;
242 break;
243
244 case FLAG_ENABLE_VTS:
245 command_flags.enable_vts = true;;
246 break;
247
248 case FLAG_NO_LOGIN:
249 command_flags.no_login = true;
250 break;
251
252 case FLAG_SPLASH_ONLY:
253 command_flags.splash_only = true;
254 break;
Dominik Behrb1abcba2016-04-14 14:57:21 -0700255 }
256 }
257
258 /* Handle resolution special before splash init. */
259 optind = 1;
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700260 for (;;) {
261 c = getopt_long(argc, argv, "", command_options, NULL);
262 if (c == -1) {
263 break;
264 } else if (c == FLAG_PRINT_RESOLUTION) {
Dominik Behr83010f82016-03-18 18:43:08 -0700265 drm_t *drm = drm_scan();
266 if (!drm)
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700267 return EXIT_FAILURE;
268
Dominik Behr83010f82016-03-18 18:43:08 -0700269 printf("%d %d", drm_gethres(drm),
270 drm_getvres(drm));
271 drm_delref(drm);
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700272 return EXIT_SUCCESS;
273 }
274 }
275
Dominik Behrb1abcba2016-04-14 14:57:21 -0700276 splash = splash_init();
277 if (splash == NULL) {
278 LOG(ERROR, "Splash init failed.");
279 return EXIT_FAILURE;
280 }
281
282 if (command_flags.daemon) {
283 splash_present_term_file(splash);
284 daemonize();
285 }
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700286
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700287 ret = input_init();
288 if (ret) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700289 LOG(ERROR, "Input init failed.");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700290 return EXIT_FAILURE;
291 }
292
Dominik Behr5239cca2016-01-21 18:22:04 -0800293 ret = dev_init();
294 if (ret) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700295 LOG(ERROR, "Device management init failed.");
Dominik Behr5239cca2016-01-21 18:22:04 -0800296 return EXIT_FAILURE;
297 }
298
Dominik Behrb1abcba2016-04-14 14:57:21 -0700299 drm_set(drm = drm_scan());
300 /* Update DRM object in splash term and set video mode. */
301 splash_redrm(splash);
David Sodmanbbcb0522014-09-19 10:34:07 -0700302
Dominik Behr0bb51772016-07-26 18:04:53 -0700303 /* These flags can be only processed after splash object has been created. */
Dominik Behrb1abcba2016-04-14 14:57:21 -0700304 optind = 1;
David Sodmanbbcb0522014-09-19 10:34:07 -0700305 for (;;) {
306 c = getopt_long(argc, argv, "", command_options, NULL);
307
308 if (c == -1)
309 break;
310
311 switch (c) {
312 case FLAG_CLEAR:
313 splash_set_clear(splash, strtoul(optarg, NULL, 0));
314 break;
315
David Sodman8ef20062015-01-06 09:23:40 -0800316 case FLAG_FRAME_INTERVAL:
317 splash_set_default_duration(splash, strtoul(optarg, NULL, 0));
318 break;
319
Dominik Behr32a7c892015-10-09 15:47:53 -0700320 case FLAG_IMAGE:
321 if (!splash_is_hires(splash))
322 splash_add_image(splash, optarg);
323 break;
324
325 case FLAG_IMAGE_HIRES:
326 if (splash_is_hires(splash))
327 splash_add_image(splash, optarg);
328 break;
329
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700330 case FLAG_LOOP_COUNT:
331 splash_set_loop_count(splash, strtoul(optarg, NULL, 0));
332 break;
333
David Sodman8ef20062015-01-06 09:23:40 -0800334 case FLAG_LOOP_START:
335 splash_set_loop_start(splash, strtoul(optarg, NULL, 0));
336 break;
337
338 case FLAG_LOOP_INTERVAL:
339 splash_set_loop_duration(splash, strtoul(optarg, NULL, 0));
340 break;
341
342 case FLAG_LOOP_OFFSET:
343 parse_offset(optarg, &x, &y);
344 splash_set_loop_offset(splash, x, y);
345 break;
346
347 case FLAG_OFFSET:
348 parse_offset(optarg, &x, &y);
349 splash_set_offset(splash, x, y);
350 break;
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700351
Dominik Behr92d9e312016-05-04 20:10:48 -0700352 case FLAG_SCALE:
353 splash_set_scale(splash, strtoul(optarg, NULL, 0));
354 break;
David Sodmanbbcb0522014-09-19 10:34:07 -0700355 }
356 }
357
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800358 for (int i = optind; i < argc; i++)
David Sodman8ef20062015-01-06 09:23:40 -0800359 splash_add_image(splash, argv[i]);
360
David Sodmanf0a925a2015-05-04 11:19:19 -0700361 if (splash_num_images(splash) > 0) {
Dominik Behr797a3832016-01-11 15:53:11 -0800362 ret = splash_run(splash);
David Sodmanbbcb0522014-09-19 10:34:07 -0700363 if (ret) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700364 LOG(ERROR, "Splash_run failed: %d.", ret);
Yuly Novikov945871e2015-05-23 00:00:41 -0400365 return EXIT_FAILURE;
David Sodmanbbcb0522014-09-19 10:34:07 -0700366 }
367 }
368
Dominik Behr0bb51772016-07-26 18:04:53 -0700369 if (command_flags.splash_only) {
370 splash_destroy(splash, false);
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700371 goto main_done;
Dominik Behr0bb51772016-07-26 18:04:53 -0700372 }
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700373
David Sodmanbbcb0522014-09-19 10:34:07 -0700374 /*
Dominik Behr46c567f2016-03-08 15:11:48 -0800375 * The DBUS service launches later than the boot-splash service, and
376 * as a result, when splash_run starts DBUS is not yet up, but, by
377 * the time splash_run completes, it is running.
Dominik Behrb1abcba2016-04-14 14:57:21 -0700378 * We really need DBUS now, so we can interact with Chrome.
David Sodmanbbcb0522014-09-19 10:34:07 -0700379 */
Dominik Behr5f6742f2016-03-10 18:03:54 -0800380 dbus_init_wait();
David Sodman8ef20062015-01-06 09:23:40 -0800381
Dominik Behr46c567f2016-03-08 15:11:48 -0800382 /*
383 * Ask DBUS to call us back so we can destroy splash (or quit) when login
Dominik Behrb1abcba2016-04-14 14:57:21 -0700384 * prompt is visible.
Dominik Behr46c567f2016-03-08 15:11:48 -0800385 */
386 dbus_set_login_prompt_visible_callback(main_on_login_prompt_visible,
387 (void*)splash);
Dominik Behr0bb51772016-07-26 18:04:53 -0700388#if !DBUS
389 splash_destroy(splash, command_flags.enable_vt1);
390#endif
Dominik Behr1883c042016-04-27 12:31:02 -0700391 /*
392 * Ask DBUS to notify us when suspend has finished so monitors can be reprobed
393 * in case they changed during suspend.
394 */
395 dbus_set_suspend_done_callback(term_suspend_done, NULL);
396
Dominik Behr46c567f2016-03-08 15:11:48 -0800397 if (command_flags.daemon) {
398 if (command_flags.enable_vts)
Dominik Behr83864df2016-04-21 12:35:08 -0700399 set_drm_master_relax(); /* TODO(dbehr) Remove when Chrome is fixed to actually release master. */
Dominik Behr0bb51772016-07-26 18:04:53 -0700400 if (!command_flags.enable_vt1)
401 term_background();
Dominik Behr46c567f2016-03-08 15:11:48 -0800402 } else {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700403 /* Create and switch to first term in interactve mode. */
Dominik Behr46c567f2016-03-08 15:11:48 -0800404 terminal_t* terminal;
Dominik Behr83864df2016-04-21 12:35:08 -0700405 set_drm_master_relax(); /* TODO(dbehr) Remove when Chrome is fixed to actually release master. */
406 term_foreground();
Dominik Behr83010f82016-03-18 18:43:08 -0700407 term_set_current_terminal(term_init(true));
Dominik Behr46c567f2016-03-08 15:11:48 -0800408 terminal = term_get_current_terminal();
409 term_activate(terminal);
410 }
411
412 ret = main_loop();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700413
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700414main_done:
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700415 input_close();
Dominik Behr5239cca2016-01-21 18:22:04 -0800416 dev_close();
Dominik Behr44e07e62016-01-13 19:43:57 -0800417 dbus_destroy();
Dominik Behr83010f82016-03-18 18:43:08 -0700418 drm_close();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700419
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700420 return ret;
421}