blob: f10099380b3cc5931ed89af0496e6d9d2eae7c16 [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 Behr46c567f2016-03-08 15:11:48 -080029#define FLAG_ENABLE_VTS 'e'
David Sodmanbbcb0522014-09-19 10:34:07 -070030#define FLAG_FRAME_INTERVAL 'f'
31#define FLAG_GAMMA 'g'
Dominik Behr32a7c892015-10-09 15:47:53 -070032#define FLAG_IMAGE 'i'
33#define FLAG_IMAGE_HIRES 'I'
Dominik Behrfd9fdda2016-03-28 17:16:45 -070034#define FLAG_LOOP_COUNT 'C'
David Sodman8ef20062015-01-06 09:23:40 -080035#define FLAG_LOOP_START 'l'
36#define FLAG_LOOP_INTERVAL 'L'
37#define FLAG_LOOP_OFFSET 'o'
38#define FLAG_OFFSET 'O'
David Sodmanbbcb0522014-09-19 10:34:07 -070039#define FLAG_PRINT_RESOLUTION 'p'
Dominik Behrfd9fdda2016-03-28 17:16:45 -070040#define FLAG_SPLASH_ONLY 's'
David Sodmanbbcb0522014-09-19 10:34:07 -070041
42static struct option command_options[] = {
43 { "clear", required_argument, NULL, FLAG_CLEAR },
44 { "daemon", no_argument, NULL, FLAG_DAEMON },
Dominik Behr46c567f2016-03-08 15:11:48 -080045 { "dev-mode", no_argument, NULL, FLAG_ENABLE_VTS },
46 { "enable-vts", no_argument, NULL, FLAG_ENABLE_VTS },
David Sodmanbbcb0522014-09-19 10:34:07 -070047 { "frame-interval", required_argument, NULL, FLAG_FRAME_INTERVAL },
48 { "gamma", required_argument, NULL, FLAG_GAMMA },
Dominik Behr32a7c892015-10-09 15:47:53 -070049 { "image", required_argument, NULL, FLAG_IMAGE },
50 { "image-hires", required_argument, NULL, FLAG_IMAGE_HIRES },
Dominik Behrfd9fdda2016-03-28 17:16:45 -070051 { "loop-count", required_argument, NULL, FLAG_LOOP_COUNT },
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 },
Dominik Behrfd9fdda2016-03-28 17:16:45 -070057 { "splash-only", no_argument, NULL, FLAG_SPLASH_ONLY },
David Sodmanbbcb0522014-09-19 10:34:07 -070058 { NULL, 0, NULL, 0 }
59};
60
Dominik Behr46c567f2016-03-08 15:11:48 -080061commandflags_t command_flags = { 0 };
Dominik Behr580462b2014-11-20 13:50:05 -080062
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080063static void parse_offset(char* param, int32_t* x, int32_t* y)
David Sodman8ef20062015-01-06 09:23:40 -080064{
65 char* token;
66 char* saveptr;
67
68 token = strtok_r(param, ",", &saveptr);
69 if (token)
70 *x = strtol(token, NULL, 0);
71
72 token = strtok_r(NULL, ",", &saveptr);
73 if (token)
74 *y = strtol(token, NULL, 0);
75}
David Sodmanbbcb0522014-09-19 10:34:07 -070076
Dominik Behr44e07e62016-01-13 19:43:57 -080077int main_process_events(uint32_t usec)
78{
79 terminal_t* terminal;
80 terminal_t* new_terminal;
81 fd_set read_set, exception_set;
Dominik Behrd7112672016-01-20 16:59:34 -080082 int maxfd = -1;
Dominik Behr44e07e62016-01-13 19:43:57 -080083 int sstat;
84 struct timeval tm;
85 struct timeval* ptm;
86
87 terminal = term_get_current_terminal();
88
89 FD_ZERO(&read_set);
90 FD_ZERO(&exception_set);
91
Dominik Behrd7112672016-01-20 16:59:34 -080092 dbus_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behrd7112672016-01-20 16:59:34 -080093 input_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr5239cca2016-01-21 18:22:04 -080094 dev_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -080095
96 for (int i = 0; i < MAX_TERMINALS; i++) {
97 if (term_is_valid(term_get_terminal(i))) {
98 terminal_t* current_term = term_get_terminal(i);
Dominik Behrd7112672016-01-20 16:59:34 -080099 term_add_fds(current_term, &read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -0800100 }
101 }
102
103 if (usec) {
104 ptm = &tm;
105 tm.tv_sec = 0;
106 tm.tv_usec = usec;
107 } else
108 ptm = NULL;
109
Dominik Behrd7112672016-01-20 16:59:34 -0800110 sstat = select(maxfd + 1, &read_set, NULL, &exception_set, ptm);
Dominik Behr44e07e62016-01-13 19:43:57 -0800111 if (sstat == 0)
112 return 0;
113
114 dbus_dispatch_io();
115
116 if (term_exception(terminal, &exception_set))
117 return -1;
118
Dominik Behr5239cca2016-01-21 18:22:04 -0800119 dev_dispatch_io(&read_set, &exception_set);
Dominik Behr44e07e62016-01-13 19:43:57 -0800120 input_dispatch_io(&read_set, &exception_set);
121
122 for (int i = 0; i < MAX_TERMINALS; i++) {
123 if (term_is_valid(term_get_terminal(i))) {
124 terminal_t* current_term = term_get_terminal(i);
125 term_dispatch_io(current_term, &read_set);
126 }
127 }
128
129 if (term_is_valid(terminal)) {
130 if (term_is_child_done(terminal)) {
131 if (terminal == term_get_terminal(SPLASH_TERMINAL)) {
132 /*
133 * Note: reference is not lost because it is still referenced
134 * by the splash_t structure which will ultimately destroy
135 * it, once it's safe to do so
136 */
137 term_set_terminal(SPLASH_TERMINAL, NULL);
138 return -1;
139 }
Dominik Behr83010f82016-03-18 18:43:08 -0700140 term_set_current_terminal(term_init(true));
Dominik Behr44e07e62016-01-13 19:43:57 -0800141 new_terminal = term_get_current_terminal();
142 if (!term_is_valid(new_terminal)) {
143 return -1;
144 }
145 term_activate(new_terminal);
146 term_close(terminal);
147 }
148 }
149
150 return 0;
151}
152
Dominik Behr46c567f2016-03-08 15:11:48 -0800153int main_loop(void)
Dominik Behr44e07e62016-01-13 19:43:57 -0800154{
Dominik Behr44e07e62016-01-13 19:43:57 -0800155 int status;
156
Dominik Behr44e07e62016-01-13 19:43:57 -0800157 while (1) {
158 status = main_process_events(0);
159 if (status != 0) {
160 LOG(ERROR, "input process returned %d", status);
161 break;
162 }
163 }
164
165 return 0;
166}
167
Dominik Behr46c567f2016-03-08 15:11:48 -0800168bool set_drm_master_relax(void)
169{
170 int fd;
171 int num_written;
172
173 /*
174 * Setting drm_master_relax flag in kernel allows us to transfer DRM master
175 * between Chrome and frecon
176 */
177 fd = open("/sys/kernel/debug/dri/drm_master_relax", O_WRONLY);
178 if (fd != -1) {
179 num_written = write(fd, "Y", 1);
180 close(fd);
181 if (num_written != 1) {
182 LOG(ERROR, "Unable to set drm_master_relax");
183 return false;
184 }
185 } else {
186 LOG(ERROR, "unable to open drm_master_relax");
187 return false;
188 }
189 return true;
190}
191
192static void main_on_login_prompt_visible(void* ptr)
193{
194 if (command_flags.daemon && !command_flags.enable_vts) {
195 exit(EXIT_SUCCESS);
196 } else
197 if (ptr) {
198 splash_destroy((splash_t*)ptr);
199 }
200}
Dominik Behr44e07e62016-01-13 19:43:57 -0800201
David Sodmanbbcb0522014-09-19 10:34:07 -0700202int main(int argc, char* argv[])
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700203{
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700204 int ret;
David Sodmanbbcb0522014-09-19 10:34:07 -0700205 int c;
David Sodman8ef20062015-01-06 09:23:40 -0800206 int32_t x, y;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800207 splash_t* splash;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700208
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700209 /* Handle resolution special before splash init */
210 for (;;) {
211 c = getopt_long(argc, argv, "", command_options, NULL);
212 if (c == -1) {
213 break;
214 } else if (c == FLAG_PRINT_RESOLUTION) {
Dominik Behr83010f82016-03-18 18:43:08 -0700215 drm_t *drm = drm_scan();
216 if (!drm)
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700217 return EXIT_FAILURE;
218
Dominik Behr83010f82016-03-18 18:43:08 -0700219 printf("%d %d", drm_gethres(drm),
220 drm_getvres(drm));
221 drm_delref(drm);
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700222 return EXIT_SUCCESS;
223 }
224 }
225
226 /* Reset option parsing */
227 optind = 1;
228
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700229 ret = input_init();
230 if (ret) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700231 LOG(ERROR, "Input init failed");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700232 return EXIT_FAILURE;
233 }
234
Dominik Behr5239cca2016-01-21 18:22:04 -0800235 ret = dev_init();
236 if (ret) {
237 LOG(ERROR, "Device management init failed");
238 return EXIT_FAILURE;
239 }
240
Dominik Behr83010f82016-03-18 18:43:08 -0700241 drm_set(drm_scan());
David Sodmanbf3f2842014-11-12 08:26:58 -0800242 splash = splash_init();
David Sodmanbbcb0522014-09-19 10:34:07 -0700243 if (splash == NULL) {
244 LOG(ERROR, "splash init failed");
245 return EXIT_FAILURE;
246 }
247
248 for (;;) {
249 c = getopt_long(argc, argv, "", command_options, NULL);
250
251 if (c == -1)
252 break;
253
254 switch (c) {
255 case FLAG_CLEAR:
256 splash_set_clear(splash, strtoul(optarg, NULL, 0));
257 break;
258
259 case FLAG_DAEMON:
Dominik Behr46c567f2016-03-08 15:11:48 -0800260 command_flags.daemon = true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700261 break;
262
David Sodman8ef20062015-01-06 09:23:40 -0800263 case FLAG_FRAME_INTERVAL:
264 splash_set_default_duration(splash, strtoul(optarg, NULL, 0));
265 break;
266
Dominik Behr46c567f2016-03-08 15:11:48 -0800267 case FLAG_ENABLE_VTS:
268 command_flags.enable_vts = true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700269 break;
270
Dominik Behr32a7c892015-10-09 15:47:53 -0700271 case FLAG_IMAGE:
272 if (!splash_is_hires(splash))
273 splash_add_image(splash, optarg);
274 break;
275
276 case FLAG_IMAGE_HIRES:
277 if (splash_is_hires(splash))
278 splash_add_image(splash, optarg);
279 break;
280
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700281 case FLAG_LOOP_COUNT:
282 splash_set_loop_count(splash, strtoul(optarg, NULL, 0));
283 break;
284
David Sodman8ef20062015-01-06 09:23:40 -0800285 case FLAG_LOOP_START:
286 splash_set_loop_start(splash, strtoul(optarg, NULL, 0));
287 break;
288
289 case FLAG_LOOP_INTERVAL:
290 splash_set_loop_duration(splash, strtoul(optarg, NULL, 0));
291 break;
292
293 case FLAG_LOOP_OFFSET:
294 parse_offset(optarg, &x, &y);
295 splash_set_loop_offset(splash, x, y);
296 break;
297
298 case FLAG_OFFSET:
299 parse_offset(optarg, &x, &y);
300 splash_set_offset(splash, x, y);
301 break;
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700302
303 case FLAG_SPLASH_ONLY:
304 command_flags.splash_only = true;
305 break;
David Sodmanbbcb0522014-09-19 10:34:07 -0700306 }
307 }
308
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800309 for (int i = optind; i < argc; i++)
David Sodman8ef20062015-01-06 09:23:40 -0800310 splash_add_image(splash, argv[i]);
311
Dominik Behr46c567f2016-03-08 15:11:48 -0800312 if (command_flags.daemon) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700313 splash_present_term_file(splash);
314 daemonize();
315 }
Dominik Behr46c567f2016-03-08 15:11:48 -0800316
David Sodmanf0a925a2015-05-04 11:19:19 -0700317 if (splash_num_images(splash) > 0) {
Dominik Behr797a3832016-01-11 15:53:11 -0800318 ret = splash_run(splash);
David Sodmanbbcb0522014-09-19 10:34:07 -0700319 if (ret) {
Yuly Novikov945871e2015-05-23 00:00:41 -0400320 LOG(ERROR, "splash_run failed: %d", ret);
321 return EXIT_FAILURE;
David Sodmanbbcb0522014-09-19 10:34:07 -0700322 }
323 }
324
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700325 if (command_flags.splash_only)
326 goto main_done;
327
David Sodmanbbcb0522014-09-19 10:34:07 -0700328 /*
Dominik Behr46c567f2016-03-08 15:11:48 -0800329 * The DBUS service launches later than the boot-splash service, and
330 * as a result, when splash_run starts DBUS is not yet up, but, by
331 * the time splash_run completes, it is running.
332 * We really need DBUS now, so we can interact with Chrome
David Sodmanbbcb0522014-09-19 10:34:07 -0700333 */
Dominik Behr5f6742f2016-03-10 18:03:54 -0800334 dbus_init_wait();
David Sodman8ef20062015-01-06 09:23:40 -0800335
Dominik Behr46c567f2016-03-08 15:11:48 -0800336 /*
337 * Ask DBUS to call us back so we can destroy splash (or quit) when login
338 * prompt is visible;
339 */
340 dbus_set_login_prompt_visible_callback(main_on_login_prompt_visible,
341 (void*)splash);
342
343 if (command_flags.daemon) {
344 if (command_flags.enable_vts)
345 set_drm_master_relax();
346 dbus_take_display_ownership();
347 } else {
Dominik Behr46c567f2016-03-08 15:11:48 -0800348 /* create and switch to first term in interactve mode */
349 terminal_t* terminal;
Dominik Behr5f6742f2016-03-10 18:03:54 -0800350 set_drm_master_relax();
Dominik Behr46c567f2016-03-08 15:11:48 -0800351 dbus_release_display_ownership();
Dominik Behr83010f82016-03-18 18:43:08 -0700352 term_set_current_terminal(term_init(true));
Dominik Behr46c567f2016-03-08 15:11:48 -0800353 terminal = term_get_current_terminal();
354 term_activate(terminal);
355 }
356
357 ret = main_loop();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700358
Dominik Behrfd9fdda2016-03-28 17:16:45 -0700359main_done:
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700360 input_close();
Dominik Behr5239cca2016-01-21 18:22:04 -0800361 dev_close();
Dominik Behr44e07e62016-01-13 19:43:57 -0800362 dbus_destroy();
Dominik Behr83010f82016-03-18 18:43:08 -0700363 drm_close();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700364
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700365 return ret;
366}