blob: bb57806e7fa1c6a78be0f02b7b5a99b730e0aecc [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
Dominik Behr797a3832016-01-11 15:53:11 -080016#include "dbus.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070017#include "dbus_interface.h"
David Sodman8ef20062015-01-06 09:23:40 -080018#include "image.h"
David Sodmanf0a925a2015-05-04 11:19:19 -070019#include "input.h"
David Sodman8ef20062015-01-06 09:23:40 -080020#include "splash.h"
David Sodmanf0a925a2015-05-04 11:19:19 -070021#include "term.h"
David Sodman8ef20062015-01-06 09:23:40 -080022#include "util.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070023
24#define MAX_SPLASH_IMAGES (30)
David Sodmandd5b23e2015-02-18 21:36:38 -080025#define MAX_SPLASH_WAITTIME (8)
David Sodman8ef20062015-01-06 09:23:40 -080026#define DBUS_WAIT_DELAY (50000)
David Sodmanbbcb0522014-09-19 10:34:07 -070027
28typedef struct {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080029 image_t* image;
30 uint32_t duration;
David Sodman8ef20062015-01-06 09:23:40 -080031} splash_frame_t;
David Sodmanbbcb0522014-09-19 10:34:07 -070032
33struct _splash_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080034 video_t* video;
35 terminal_t* terminal;
36 int num_images;
37 uint32_t clear;
38 splash_frame_t image_frames[MAX_SPLASH_IMAGES];
39 bool terminated;
40 bool devmode;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080041 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
Dominik Behr797a3832016-01-11 15:53:11 -0800123int splash_run(splash_t* splash)
David Sodmanbbcb0522014-09-19 10:34:07 -0700124{
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 }
Dominik Behr4defb362016-01-13 12:36:14 -0800177 status = input_process(1);
David Sodmanf0a925a2015-05-04 11:19:19 -0700178 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
Dominik Behr4defb362016-01-13 12:36:14 -0800197 term_set_current_to(NULL);
David Sodmanf0a925a2015-05-04 11:19:19 -0700198
199 /*
200 * Now Chrome can take over
201 */
202 video_release(splash->video);
203 video_unlock(splash->video);
204
Dominik Behr797a3832016-01-11 15:53:11 -0800205 while (!dbus_is_initialized()) {
206 dbus_init();
207 usleep(DBUS_WAIT_DELAY);
David Sodmanf0a925a2015-05-04 11:19:19 -0700208 }
209
210 if (splash->devmode) {
David Sodman5c9afa72015-02-14 09:32:53 -0800211 /*
David Sodmanf0a925a2015-05-04 11:19:19 -0700212 * Now set drm_master_relax so that we can transfer drm_master between
213 * chrome and frecon
David Sodman5c9afa72015-02-14 09:32:53 -0800214 */
David Sodmanf0a925a2015-05-04 11:19:19 -0700215 fd = open("/sys/kernel/debug/dri/drm_master_relax", O_WRONLY);
216 if (fd != -1) {
217 num_written = write(fd, "Y", 1);
218 close(fd);
David Sodmanbbcb0522014-09-19 10:34:07 -0700219
David Sodmanbbcb0522014-09-19 10:34:07 -0700220 /*
David Sodmanf0a925a2015-05-04 11:19:19 -0700221 * If we can't set drm_master relax, then transitions between chrome
222 * and frecon won't work. No point in having frecon hold any resources
David Sodmanbbcb0522014-09-19 10:34:07 -0700223 */
David Sodmanf0a925a2015-05-04 11:19:19 -0700224 if (num_written != 1) {
225 LOG(ERROR, "Unable to set drm_master_relax");
226 splash->devmode = false;
David Sodmanbbcb0522014-09-19 10:34:07 -0700227 }
David Sodmandd5b23e2015-02-18 21:36:38 -0800228 } else {
David Sodmanf0a925a2015-05-04 11:19:19 -0700229 LOG(ERROR, "unable to open drm_master_relax");
David Sodmanbbcb0522014-09-19 10:34:07 -0700230 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700231 } else {
232 /*
233 * Below, we will wait for Chrome to appear above the splash
234 * image. If we are not in dev mode, wait and then exit
235 */
236 sleep(MAX_SPLASH_WAITTIME);
237 exit(EXIT_SUCCESS);
David Sodmanbbcb0522014-09-19 10:34:07 -0700238 }
David Sodman003faed2014-11-03 09:02:10 -0800239
Dominik Behr797a3832016-01-11 15:53:11 -0800240 dbus_take_display_ownership();
David Sodmanf348b0d2015-02-10 08:34:57 -0800241
242 /*
243 * Finally, wait until chrome has drawn on top of the splash. In dev mode,
244 * wait a few seconds for chrome to show up.
245 */
246 sleep(MAX_SPLASH_WAITTIME);
David Sodmanbbcb0522014-09-19 10:34:07 -0700247 return status;
248}
249
David Sodman8ef20062015-01-06 09:23:40 -0800250void splash_set_offset(splash_t* splash, int32_t x, int32_t y)
251{
252 if (splash) {
253 splash->offset_x = x;
254 splash->offset_y = y;
255 }
256}
257
David Sodmanbbcb0522014-09-19 10:34:07 -0700258void splash_set_devmode(splash_t* splash)
259{
David Sodman8ef20062015-01-06 09:23:40 -0800260 if (splash)
261 splash->devmode = true;
262}
263
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800264int splash_num_images(splash_t* splash)
David Sodman8ef20062015-01-06 09:23:40 -0800265{
266 if (splash)
267 return splash->num_images;
268
269 return 0;
270}
271
272void splash_set_default_duration(splash_t* splash, uint32_t duration)
273{
274 if (splash)
275 splash->default_duration = duration;
276}
277
278void splash_set_loop_start(splash_t* splash, int32_t loop_start)
279{
280 if (splash)
281 splash->loop_start = loop_start;
282}
283
284void splash_set_loop_duration(splash_t* splash, uint32_t duration)
285{
286 if (splash)
287 splash->loop_duration = duration;
288}
289
290void splash_set_loop_offset(splash_t* splash, int32_t x, int32_t y)
291{
292 if (splash) {
293 splash->loop_offset_x = x;
294 splash->loop_offset_y = y;
295 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700296}
David Sodmanf0a925a2015-05-04 11:19:19 -0700297
298void splash_present_term_file(splash_t* splash)
299{
300 fprintf(stdout, "%s\n", term_get_ptsname(splash->terminal));
301}
Dominik Behr32a7c892015-10-09 15:47:53 -0700302
303int splash_is_hires(splash_t* splash)
304{
305 if (splash && splash->video)
306 return video_getwidth(splash->video) > 1920;
307 return 0;
308}