blob: cec1b86eb36c67a940a9e6f206d70692140326c0 [file] [log] [blame]
David Sodmanbbcb0522014-09-19 10:34:07 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
David Sodman8ef20062015-01-06 09:23:40 -08007#include <fcntl.h>
David Sodmanbbcb0522014-09-19 10:34:07 -07008#include <stdbool.h>
9#include <stddef.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <sys/mman.h>
14#include <unistd.h>
David Sodmanbbcb0522014-09-19 10:34:07 -070015
David Sodmanbbcb0522014-09-19 10:34:07 -070016#include "dbus_interface.h"
David Sodman8ef20062015-01-06 09:23:40 -080017#include "image.h"
David Sodmanf0a925a2015-05-04 11:19:19 -070018#include "input.h"
David Sodman8ef20062015-01-06 09:23:40 -080019#include "splash.h"
David Sodmanf0a925a2015-05-04 11:19:19 -070020#include "term.h"
David Sodman8ef20062015-01-06 09:23:40 -080021#include "util.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070022
23#define MAX_SPLASH_IMAGES (30)
David Sodmandd5b23e2015-02-18 21:36:38 -080024#define MAX_SPLASH_WAITTIME (8)
David Sodman8ef20062015-01-06 09:23:40 -080025#define DBUS_WAIT_DELAY (50000)
David Sodmanbbcb0522014-09-19 10:34:07 -070026
27typedef struct {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080028 image_t* image;
29 uint32_t duration;
David Sodman8ef20062015-01-06 09:23:40 -080030} splash_frame_t;
David Sodmanbbcb0522014-09-19 10:34:07 -070031
32struct _splash_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080033 video_t* video;
34 terminal_t* terminal;
35 int num_images;
36 uint32_t clear;
37 splash_frame_t image_frames[MAX_SPLASH_IMAGES];
38 bool terminated;
39 bool devmode;
40 dbus_t* dbus;
41 int32_t loop_start;
42 uint32_t loop_duration;
43 uint32_t default_duration;
44 int32_t offset_x;
45 int32_t offset_y;
46 int32_t loop_offset_x;
47 int32_t loop_offset_y;
David Sodmanbbcb0522014-09-19 10:34:07 -070048};
49
David Sodmanbf3f2842014-11-12 08:26:58 -080050
51splash_t* splash_init()
David Sodmanbbcb0522014-09-19 10:34:07 -070052{
53 splash_t* splash;
54
55 splash = (splash_t*)calloc(1, sizeof(splash_t));
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -080056 if (!splash)
David Sodmanbbcb0522014-09-19 10:34:07 -070057 return NULL;
58
David Sodmanbf3f2842014-11-12 08:26:58 -080059 splash->video = video_init();
Yuly Novikov945871e2015-05-23 00:00:41 -040060 if (!splash->video) {
61 free(splash);
62 return NULL;
63 }
64
Stéphane Marchesinf75c8512016-01-07 16:53:21 -080065 splash->terminal = term_create_splash_term(splash->video);
David Sodman8ef20062015-01-06 09:23:40 -080066 splash->loop_start = -1;
67 splash->default_duration = 25;
68 splash->loop_duration = 25;
David Sodmanbbcb0522014-09-19 10:34:07 -070069
70 return splash;
71}
72
73int splash_destroy(splash_t* splash)
74{
David Sodmanf0a925a2015-05-04 11:19:19 -070075 if (splash->terminal) {
76 term_close(splash->terminal);
77 splash->terminal = NULL;
David Sodman8ef20062015-01-06 09:23:40 -080078 }
79 free(splash);
Stéphane Marchesinf75c8512016-01-07 16:53:21 -080080 term_destroy_splash_term();
David Sodmanbbcb0522014-09-19 10:34:07 -070081 return 0;
82}
83
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080084int splash_set_clear(splash_t* splash, uint32_t clear_color)
David Sodmanbbcb0522014-09-19 10:34:07 -070085{
86 splash->clear = clear_color;
87 return 0;
88}
89
David Sodman8ef20062015-01-06 09:23:40 -080090int splash_add_image(splash_t* splash, char* filespec)
David Sodmanbbcb0522014-09-19 10:34:07 -070091{
David Sodman8ef20062015-01-06 09:23:40 -080092 image_t* image;
93 int32_t offset_x, offset_y;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080094 char* filename;
David Sodman8ef20062015-01-06 09:23:40 -080095 uint32_t duration;
David Sodmanbbcb0522014-09-19 10:34:07 -070096 if (splash->num_images >= MAX_SPLASH_IMAGES)
97 return 1;
98
David Sodman8ef20062015-01-06 09:23:40 -080099 filename = (char*)malloc(strlen(filespec) + 1);
100 parse_filespec(filespec,
101 filename,
102 &offset_x, &offset_y, &duration,
103 splash->default_duration,
104 splash->offset_x,
105 splash->offset_y);
106
107 image = image_create();
108 image_set_filename(image, filename);
109 image_set_offset(image, offset_x, offset_y);
110 splash->image_frames[splash->num_images].image = image;
111 splash->image_frames[splash->num_images].duration = duration;
David Sodmanbbcb0522014-09-19 10:34:07 -0700112 splash->num_images++;
David Sodman8ef20062015-01-06 09:23:40 -0800113
114 free(filename);
David Sodmanbbcb0522014-09-19 10:34:07 -0700115 return 0;
116}
117
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800118static void splash_clear_screen(splash_t* splash)
David Sodmanbbcb0522014-09-19 10:34:07 -0700119{
David Sodmanf0a925a2015-05-04 11:19:19 -0700120 term_set_background(splash->terminal, splash->clear);
David Sodmanbbcb0522014-09-19 10:34:07 -0700121}
122
123int splash_run(splash_t* splash, dbus_t** dbus)
124{
125 int i;
David Sodmanbbcb0522014-09-19 10:34:07 -0700126 int status;
David Sodmanbbcb0522014-09-19 10:34:07 -0700127 int64_t last_show_ms;
128 int64_t now_ms;
129 int64_t sleep_ms;
130 struct timespec sleep_spec;
131 int fd;
132 int num_written;
David Sodman8ef20062015-01-06 09:23:40 -0800133 image_t* image;
134 uint32_t duration;
David Sodmanbbcb0522014-09-19 10:34:07 -0700135
David Sodmanbbcb0522014-09-19 10:34:07 -0700136 /*
137 * First draw the actual splash screen
138 */
David Sodmanf0a925a2015-05-04 11:19:19 -0700139 splash_clear_screen(splash);
140 term_activate(splash->terminal);
141 last_show_ms = -1;
142 for (i = 0; i < splash->num_images; i++) {
143 image = splash->image_frames[i].image;
144 status = image_load_image_from_file(image);
145 if (status != 0) {
146 LOG(WARNING, "image_load_image_from_file failed: %d", status);
147 break;
David Sodman8ef20062015-01-06 09:23:40 -0800148 }
149
David Sodmanf0a925a2015-05-04 11:19:19 -0700150 now_ms = get_monotonic_time_ms();
151 if (last_show_ms > 0) {
152 if (splash->loop_start >= 0 && i >= splash->loop_start)
153 duration = splash->loop_duration;
154 else
155 duration = splash->image_frames[i].duration;
156 sleep_ms = duration - (now_ms - last_show_ms);
157 if (sleep_ms > 0) {
158 sleep_spec.tv_sec = sleep_ms / MS_PER_SEC;
159 sleep_spec.tv_nsec = (sleep_ms % MS_PER_SEC) * NS_PER_MS;
160 nanosleep(&sleep_spec, NULL);
161 }
162 }
163
164 now_ms = get_monotonic_time_ms();
165
166 if (i >= splash->loop_start) {
167 image_set_offset(image,
168 splash->loop_offset_x,
169 splash->loop_offset_y);
170 }
171
172 status = term_show_image(splash->terminal, image);
173 if (status != 0) {
174 LOG(WARNING, "term_show_image failed: %d", status);
175 break;
176 }
177 status = input_process(splash->terminal, 1);
178 if (status != 0) {
179 LOG(WARNING, "input_process failed: %d", status);
180 break;
181 }
182 last_show_ms = now_ms;
183
184 if ((splash->loop_start >= 0) &&
185 (splash->loop_start < splash->num_images)) {
186 if (i == splash->num_images - 1)
187 i = splash->loop_start - 1;
188 }
189
190 image_release(image);
191 }
192
193 for (i = 0; i < splash->num_images; i++) {
194 image_destroy(splash->image_frames[i].image);
195 }
196
197 input_set_current(NULL);
198
199 /*
200 * Now Chrome can take over
201 */
202 video_release(splash->video);
203 video_unlock(splash->video);
204
205 if (dbus != NULL) {
206 do {
207 *dbus = dbus_init();
208 usleep(DBUS_WAIT_DELAY);
209 } while (*dbus == NULL);
210 splash_set_dbus(splash, *dbus);
211 }
212
213 if (splash->devmode) {
David Sodman5c9afa72015-02-14 09:32:53 -0800214 /*
David Sodmanf0a925a2015-05-04 11:19:19 -0700215 * Now set drm_master_relax so that we can transfer drm_master between
216 * chrome and frecon
David Sodman5c9afa72015-02-14 09:32:53 -0800217 */
David Sodmanf0a925a2015-05-04 11:19:19 -0700218 fd = open("/sys/kernel/debug/dri/drm_master_relax", O_WRONLY);
219 if (fd != -1) {
220 num_written = write(fd, "Y", 1);
221 close(fd);
David Sodmanbbcb0522014-09-19 10:34:07 -0700222
David Sodmanbbcb0522014-09-19 10:34:07 -0700223 /*
David Sodmanf0a925a2015-05-04 11:19:19 -0700224 * If we can't set drm_master relax, then transitions between chrome
225 * and frecon won't work. No point in having frecon hold any resources
David Sodmanbbcb0522014-09-19 10:34:07 -0700226 */
David Sodmanf0a925a2015-05-04 11:19:19 -0700227 if (num_written != 1) {
228 LOG(ERROR, "Unable to set drm_master_relax");
229 splash->devmode = false;
David Sodmanbbcb0522014-09-19 10:34:07 -0700230 }
David Sodmandd5b23e2015-02-18 21:36:38 -0800231 } else {
David Sodmanf0a925a2015-05-04 11:19:19 -0700232 LOG(ERROR, "unable to open drm_master_relax");
David Sodmanbbcb0522014-09-19 10:34:07 -0700233 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700234 } else {
235 /*
236 * Below, we will wait for Chrome to appear above the splash
237 * image. If we are not in dev mode, wait and then exit
238 */
239 sleep(MAX_SPLASH_WAITTIME);
240 exit(EXIT_SUCCESS);
David Sodmanbbcb0522014-09-19 10:34:07 -0700241 }
David Sodman003faed2014-11-03 09:02:10 -0800242
David Sodman8ef20062015-01-06 09:23:40 -0800243 if (splash->dbus) {
244 (void)dbus_method_call0(splash->dbus,
245 kLibCrosServiceName,
246 kLibCrosServicePath,
247 kLibCrosServiceInterface,
248 kTakeDisplayOwnership);
249 }
David Sodmanf348b0d2015-02-10 08:34:57 -0800250
251 /*
252 * Finally, wait until chrome has drawn on top of the splash. In dev mode,
253 * wait a few seconds for chrome to show up.
254 */
255 sleep(MAX_SPLASH_WAITTIME);
David Sodmanbbcb0522014-09-19 10:34:07 -0700256 return status;
257}
258
David Sodman8ef20062015-01-06 09:23:40 -0800259void splash_set_offset(splash_t* splash, int32_t x, int32_t y)
260{
261 if (splash) {
262 splash->offset_x = x;
263 splash->offset_y = y;
264 }
265}
266
David Sodmanbbcb0522014-09-19 10:34:07 -0700267void splash_set_dbus(splash_t* splash, dbus_t* dbus)
268{
David Sodman8ef20062015-01-06 09:23:40 -0800269 if (splash)
270 splash->dbus = dbus;
David Sodmanbbcb0522014-09-19 10:34:07 -0700271}
272
273void splash_set_devmode(splash_t* splash)
274{
David Sodman8ef20062015-01-06 09:23:40 -0800275 if (splash)
276 splash->devmode = true;
277}
278
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800279int splash_num_images(splash_t* splash)
David Sodman8ef20062015-01-06 09:23:40 -0800280{
281 if (splash)
282 return splash->num_images;
283
284 return 0;
285}
286
287void splash_set_default_duration(splash_t* splash, uint32_t duration)
288{
289 if (splash)
290 splash->default_duration = duration;
291}
292
293void splash_set_loop_start(splash_t* splash, int32_t loop_start)
294{
295 if (splash)
296 splash->loop_start = loop_start;
297}
298
299void splash_set_loop_duration(splash_t* splash, uint32_t duration)
300{
301 if (splash)
302 splash->loop_duration = duration;
303}
304
305void splash_set_loop_offset(splash_t* splash, int32_t x, int32_t y)
306{
307 if (splash) {
308 splash->loop_offset_x = x;
309 splash->loop_offset_y = y;
310 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700311}
David Sodmanf0a925a2015-05-04 11:19:19 -0700312
313void splash_present_term_file(splash_t* splash)
314{
315 fprintf(stdout, "%s\n", term_get_ptsname(splash->terminal));
316}
Dominik Behr32a7c892015-10-09 15:47:53 -0700317
318int splash_is_hires(splash_t* splash)
319{
320 if (splash && splash->video)
321 return video_getwidth(splash->video) > 1920;
322 return 0;
323}