blob: 6ac9ddbafcd23409b8940dd1e1f13f9e6c2e87f6 [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
David Sodmanbbcb0522014-09-19 10:34:07 -070028#define FLAG_CLEAR 'c'
29#define FLAG_DAEMON 'd'
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'
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'
40
41static struct option command_options[] = {
42 { "clear", required_argument, NULL, FLAG_CLEAR },
43 { "daemon", no_argument, NULL, FLAG_DAEMON },
Dominik Behr46c567f2016-03-08 15:11:48 -080044 { "dev-mode", no_argument, NULL, FLAG_ENABLE_VTS },
45 { "enable-vts", no_argument, NULL, FLAG_ENABLE_VTS },
David Sodmanbbcb0522014-09-19 10:34:07 -070046 { "frame-interval", required_argument, NULL, FLAG_FRAME_INTERVAL },
47 { "gamma", required_argument, NULL, FLAG_GAMMA },
Dominik Behr32a7c892015-10-09 15:47:53 -070048 { "image", required_argument, NULL, FLAG_IMAGE },
49 { "image-hires", required_argument, NULL, FLAG_IMAGE_HIRES },
David Sodman8ef20062015-01-06 09:23:40 -080050 { "loop-start", required_argument, NULL, FLAG_LOOP_START },
51 { "loop-interval", required_argument, NULL, FLAG_LOOP_INTERVAL },
52 { "loop-offset", required_argument, NULL, FLAG_LOOP_OFFSET },
53 { "offset", required_argument, NULL, FLAG_OFFSET },
David Sodmanbbcb0522014-09-19 10:34:07 -070054 { "print-resolution", no_argument, NULL, FLAG_PRINT_RESOLUTION },
55 { NULL, 0, NULL, 0 }
56};
57
Dominik Behr46c567f2016-03-08 15:11:48 -080058commandflags_t command_flags = { 0 };
Dominik Behr580462b2014-11-20 13:50:05 -080059
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080060static void parse_offset(char* param, int32_t* x, int32_t* y)
David Sodman8ef20062015-01-06 09:23:40 -080061{
62 char* token;
63 char* saveptr;
64
65 token = strtok_r(param, ",", &saveptr);
66 if (token)
67 *x = strtol(token, NULL, 0);
68
69 token = strtok_r(NULL, ",", &saveptr);
70 if (token)
71 *y = strtol(token, NULL, 0);
72}
David Sodmanbbcb0522014-09-19 10:34:07 -070073
Dominik Behr44e07e62016-01-13 19:43:57 -080074int main_process_events(uint32_t usec)
75{
76 terminal_t* terminal;
77 terminal_t* new_terminal;
78 fd_set read_set, exception_set;
Dominik Behrd7112672016-01-20 16:59:34 -080079 int maxfd = -1;
Dominik Behr44e07e62016-01-13 19:43:57 -080080 int sstat;
81 struct timeval tm;
82 struct timeval* ptm;
83
84 terminal = term_get_current_terminal();
85
86 FD_ZERO(&read_set);
87 FD_ZERO(&exception_set);
88
Dominik Behrd7112672016-01-20 16:59:34 -080089 dbus_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behrd7112672016-01-20 16:59:34 -080090 input_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr5239cca2016-01-21 18:22:04 -080091 dev_add_fds(&read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -080092
93 for (int i = 0; i < MAX_TERMINALS; i++) {
94 if (term_is_valid(term_get_terminal(i))) {
95 terminal_t* current_term = term_get_terminal(i);
Dominik Behrd7112672016-01-20 16:59:34 -080096 term_add_fds(current_term, &read_set, &exception_set, &maxfd);
Dominik Behr44e07e62016-01-13 19:43:57 -080097 }
98 }
99
100 if (usec) {
101 ptm = &tm;
102 tm.tv_sec = 0;
103 tm.tv_usec = usec;
104 } else
105 ptm = NULL;
106
Dominik Behrd7112672016-01-20 16:59:34 -0800107 sstat = select(maxfd + 1, &read_set, NULL, &exception_set, ptm);
Dominik Behr44e07e62016-01-13 19:43:57 -0800108 if (sstat == 0)
109 return 0;
110
111 dbus_dispatch_io();
112
113 if (term_exception(terminal, &exception_set))
114 return -1;
115
Dominik Behr5239cca2016-01-21 18:22:04 -0800116 dev_dispatch_io(&read_set, &exception_set);
Dominik Behr44e07e62016-01-13 19:43:57 -0800117 input_dispatch_io(&read_set, &exception_set);
118
119 for (int i = 0; i < MAX_TERMINALS; i++) {
120 if (term_is_valid(term_get_terminal(i))) {
121 terminal_t* current_term = term_get_terminal(i);
122 term_dispatch_io(current_term, &read_set);
123 }
124 }
125
126 if (term_is_valid(terminal)) {
127 if (term_is_child_done(terminal)) {
128 if (terminal == term_get_terminal(SPLASH_TERMINAL)) {
129 /*
130 * Note: reference is not lost because it is still referenced
131 * by the splash_t structure which will ultimately destroy
132 * it, once it's safe to do so
133 */
134 term_set_terminal(SPLASH_TERMINAL, NULL);
135 return -1;
136 }
137 term_set_current_terminal(term_init(true, term_getvideo(terminal)));
138 new_terminal = term_get_current_terminal();
139 if (!term_is_valid(new_terminal)) {
140 return -1;
141 }
142 term_activate(new_terminal);
143 term_close(terminal);
144 }
145 }
146
147 return 0;
148}
149
Dominik Behr46c567f2016-03-08 15:11:48 -0800150int main_loop(void)
Dominik Behr44e07e62016-01-13 19:43:57 -0800151{
Dominik Behr44e07e62016-01-13 19:43:57 -0800152 int status;
153
Dominik Behr44e07e62016-01-13 19:43:57 -0800154 while (1) {
155 status = main_process_events(0);
156 if (status != 0) {
157 LOG(ERROR, "input process returned %d", status);
158 break;
159 }
160 }
161
162 return 0;
163}
164
Dominik Behr46c567f2016-03-08 15:11:48 -0800165bool set_drm_master_relax(void)
166{
167 int fd;
168 int num_written;
169
170 /*
171 * Setting drm_master_relax flag in kernel allows us to transfer DRM master
172 * between Chrome and frecon
173 */
174 fd = open("/sys/kernel/debug/dri/drm_master_relax", O_WRONLY);
175 if (fd != -1) {
176 num_written = write(fd, "Y", 1);
177 close(fd);
178 if (num_written != 1) {
179 LOG(ERROR, "Unable to set drm_master_relax");
180 return false;
181 }
182 } else {
183 LOG(ERROR, "unable to open drm_master_relax");
184 return false;
185 }
186 return true;
187}
188
189static void main_on_login_prompt_visible(void* ptr)
190{
191 if (command_flags.daemon && !command_flags.enable_vts) {
192 exit(EXIT_SUCCESS);
193 } else
194 if (ptr) {
195 splash_destroy((splash_t*)ptr);
196 }
197}
Dominik Behr44e07e62016-01-13 19:43:57 -0800198
David Sodmanbbcb0522014-09-19 10:34:07 -0700199int main(int argc, char* argv[])
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700200{
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700201 int ret;
David Sodmanbbcb0522014-09-19 10:34:07 -0700202 int c;
David Sodman8ef20062015-01-06 09:23:40 -0800203 int32_t x, y;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800204 splash_t* splash;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700205
Douglas Anderson4da95cd2015-10-05 15:04:30 -0700206 /* Handle resolution special before splash init */
207 for (;;) {
208 c = getopt_long(argc, argv, "", command_options, NULL);
209 if (c == -1) {
210 break;
211 } else if (c == FLAG_PRINT_RESOLUTION) {
212 video_t *video = video_init();
213 if (!video)
214 return EXIT_FAILURE;
215
216 printf("%d %d", video_getwidth(video),
217 video_getheight(video));
218 video_close(video);
219 return EXIT_SUCCESS;
220 }
221 }
222
223 /* Reset option parsing */
224 optind = 1;
225
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700226 ret = input_init();
227 if (ret) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700228 LOG(ERROR, "Input init failed");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700229 return EXIT_FAILURE;
230 }
231
Dominik Behr5239cca2016-01-21 18:22:04 -0800232 ret = dev_init();
233 if (ret) {
234 LOG(ERROR, "Device management init failed");
235 return EXIT_FAILURE;
236 }
237
David Sodmanbf3f2842014-11-12 08:26:58 -0800238 splash = splash_init();
David Sodmanbbcb0522014-09-19 10:34:07 -0700239 if (splash == NULL) {
240 LOG(ERROR, "splash init failed");
241 return EXIT_FAILURE;
242 }
243
244 for (;;) {
245 c = getopt_long(argc, argv, "", command_options, NULL);
246
247 if (c == -1)
248 break;
249
250 switch (c) {
251 case FLAG_CLEAR:
252 splash_set_clear(splash, strtoul(optarg, NULL, 0));
253 break;
254
255 case FLAG_DAEMON:
Dominik Behr46c567f2016-03-08 15:11:48 -0800256 command_flags.daemon = true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700257 break;
258
David Sodman8ef20062015-01-06 09:23:40 -0800259 case FLAG_FRAME_INTERVAL:
260 splash_set_default_duration(splash, strtoul(optarg, NULL, 0));
261 break;
262
Dominik Behr46c567f2016-03-08 15:11:48 -0800263 case FLAG_ENABLE_VTS:
264 command_flags.enable_vts = true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700265 break;
266
Dominik Behr32a7c892015-10-09 15:47:53 -0700267 case FLAG_IMAGE:
268 if (!splash_is_hires(splash))
269 splash_add_image(splash, optarg);
270 break;
271
272 case FLAG_IMAGE_HIRES:
273 if (splash_is_hires(splash))
274 splash_add_image(splash, optarg);
275 break;
276
David Sodman8ef20062015-01-06 09:23:40 -0800277 case FLAG_LOOP_START:
278 splash_set_loop_start(splash, strtoul(optarg, NULL, 0));
279 break;
280
281 case FLAG_LOOP_INTERVAL:
282 splash_set_loop_duration(splash, strtoul(optarg, NULL, 0));
283 break;
284
285 case FLAG_LOOP_OFFSET:
286 parse_offset(optarg, &x, &y);
287 splash_set_loop_offset(splash, x, y);
288 break;
289
290 case FLAG_OFFSET:
291 parse_offset(optarg, &x, &y);
292 splash_set_offset(splash, x, y);
293 break;
David Sodmanbbcb0522014-09-19 10:34:07 -0700294 }
295 }
296
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800297 for (int i = optind; i < argc; i++)
David Sodman8ef20062015-01-06 09:23:40 -0800298 splash_add_image(splash, argv[i]);
299
Dominik Behr46c567f2016-03-08 15:11:48 -0800300 if (command_flags.daemon) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700301 splash_present_term_file(splash);
302 daemonize();
303 }
Dominik Behr46c567f2016-03-08 15:11:48 -0800304
David Sodmanf0a925a2015-05-04 11:19:19 -0700305 if (splash_num_images(splash) > 0) {
Dominik Behr797a3832016-01-11 15:53:11 -0800306 ret = splash_run(splash);
David Sodmanbbcb0522014-09-19 10:34:07 -0700307 if (ret) {
Yuly Novikov945871e2015-05-23 00:00:41 -0400308 LOG(ERROR, "splash_run failed: %d", ret);
309 return EXIT_FAILURE;
David Sodmanbbcb0522014-09-19 10:34:07 -0700310 }
311 }
312
313 /*
Dominik Behr46c567f2016-03-08 15:11:48 -0800314 * The DBUS service launches later than the boot-splash service, and
315 * as a result, when splash_run starts DBUS is not yet up, but, by
316 * the time splash_run completes, it is running.
317 * We really need DBUS now, so we can interact with Chrome
David Sodmanbbcb0522014-09-19 10:34:07 -0700318 */
Dominik Behr5f6742f2016-03-10 18:03:54 -0800319 dbus_init_wait();
David Sodman8ef20062015-01-06 09:23:40 -0800320
Dominik Behr46c567f2016-03-08 15:11:48 -0800321 /*
322 * Ask DBUS to call us back so we can destroy splash (or quit) when login
323 * prompt is visible;
324 */
325 dbus_set_login_prompt_visible_callback(main_on_login_prompt_visible,
326 (void*)splash);
327
328 if (command_flags.daemon) {
329 if (command_flags.enable_vts)
330 set_drm_master_relax();
331 dbus_take_display_ownership();
332 } else {
Dominik Behr46c567f2016-03-08 15:11:48 -0800333 /* create and switch to first term in interactve mode */
334 terminal_t* terminal;
Dominik Behr5f6742f2016-03-10 18:03:54 -0800335 set_drm_master_relax();
Dominik Behr46c567f2016-03-08 15:11:48 -0800336 dbus_release_display_ownership();
337 term_set_current_terminal(term_init(true, NULL));
338 terminal = term_get_current_terminal();
339 term_activate(terminal);
340 }
341
342 ret = main_loop();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700343
344 input_close();
Dominik Behr5239cca2016-01-21 18:22:04 -0800345 dev_close();
Dominik Behr44e07e62016-01-13 19:43:57 -0800346 dbus_destroy();
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700347
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700348 return ret;
349}