blob: 5d53029006cd72ac63124a2262226bfb1ed1dd88 [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 {
David Sodman8ef20062015-01-06 09:23:40 -080028 image_t *image;
29 uint32_t duration;
30} splash_frame_t;
David Sodmanbbcb0522014-09-19 10:34:07 -070031
32struct _splash_t {
33 video_t *video;
David Sodmanf0a925a2015-05-04 11:19:19 -070034 terminal_t *terminal;
David Sodmanbbcb0522014-09-19 10:34:07 -070035 int num_images;
David Sodmanbbcb0522014-09-19 10:34:07 -070036 uint32_t clear;
David Sodmanf0a925a2015-05-04 11:19:19 -070037 splash_frame_t image_frames[MAX_SPLASH_IMAGES];
David Sodmanbbcb0522014-09-19 10:34:07 -070038 bool terminated;
39 bool devmode;
40 dbus_t *dbus;
David Sodman8ef20062015-01-06 09:23:40 -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;
David Sodman73e82272014-11-17 10:11:47 -080054 FILE *cookie_fp;
David Sodmanbbcb0522014-09-19 10:34:07 -070055
56 splash = (splash_t*)calloc(1, sizeof(splash_t));
57 if (splash == NULL)
58 return NULL;
59
David Sodmanbf3f2842014-11-12 08:26:58 -080060 splash->video = video_init();
David Sodmanf0a925a2015-05-04 11:19:19 -070061 splash->terminal = input_create_splash_term(splash->video);
David Sodman8ef20062015-01-06 09:23:40 -080062 splash->loop_start = -1;
63 splash->default_duration = 25;
64 splash->loop_duration = 25;
David Sodmanbbcb0522014-09-19 10:34:07 -070065
David Sodmanf0a925a2015-05-04 11:19:19 -070066 // Hide the cursor on the splash screen
67 term_hide_cursor(splash->terminal);
68
David Sodman73e82272014-11-17 10:11:47 -080069 cookie_fp = fopen("/tmp/display_info.bin", "wb");
70 if (cookie_fp) {
71 fwrite(&splash->video->internal_panel, sizeof(char), 1, cookie_fp);
72 fwrite(splash->video->edid, EDID_SIZE, 1, cookie_fp);
73 fclose(cookie_fp);
74 }
75
David Sodmanbbcb0522014-09-19 10:34:07 -070076 return splash;
77}
78
79int splash_destroy(splash_t* splash)
80{
David Sodmanf0a925a2015-05-04 11:19:19 -070081 if (splash->terminal) {
82 term_close(splash->terminal);
83 splash->terminal = NULL;
David Sodman8ef20062015-01-06 09:23:40 -080084 }
85 free(splash);
David Sodmanf0a925a2015-05-04 11:19:19 -070086 input_destroy_splash_term();
David Sodmanbbcb0522014-09-19 10:34:07 -070087 return 0;
88}
89
David Sodmanf0a925a2015-05-04 11:19:19 -070090int splash_set_clear(splash_t *splash, uint32_t clear_color)
David Sodmanbbcb0522014-09-19 10:34:07 -070091{
92 splash->clear = clear_color;
93 return 0;
94}
95
David Sodman8ef20062015-01-06 09:23:40 -080096int splash_add_image(splash_t* splash, char* filespec)
David Sodmanbbcb0522014-09-19 10:34:07 -070097{
David Sodman8ef20062015-01-06 09:23:40 -080098 image_t* image;
99 int32_t offset_x, offset_y;
100 char *filename;
101 uint32_t duration;
David Sodmanbbcb0522014-09-19 10:34:07 -0700102 if (splash->num_images >= MAX_SPLASH_IMAGES)
103 return 1;
104
David Sodman8ef20062015-01-06 09:23:40 -0800105 filename = (char*)malloc(strlen(filespec) + 1);
106 parse_filespec(filespec,
107 filename,
108 &offset_x, &offset_y, &duration,
109 splash->default_duration,
110 splash->offset_x,
111 splash->offset_y);
112
113 image = image_create();
114 image_set_filename(image, filename);
115 image_set_offset(image, offset_x, offset_y);
116 splash->image_frames[splash->num_images].image = image;
117 splash->image_frames[splash->num_images].duration = duration;
David Sodmanbbcb0522014-09-19 10:34:07 -0700118 splash->num_images++;
David Sodman8ef20062015-01-06 09:23:40 -0800119
120 free(filename);
David Sodmanbbcb0522014-09-19 10:34:07 -0700121 return 0;
122}
123
David Sodmanf0a925a2015-05-04 11:19:19 -0700124static void splash_clear_screen(splash_t *splash)
David Sodmanbbcb0522014-09-19 10:34:07 -0700125{
David Sodmanf0a925a2015-05-04 11:19:19 -0700126 term_set_background(splash->terminal, splash->clear);
David Sodmanbbcb0522014-09-19 10:34:07 -0700127}
128
129int splash_run(splash_t* splash, dbus_t** dbus)
130{
131 int i;
David Sodmanbbcb0522014-09-19 10:34:07 -0700132 int status;
David Sodmanbbcb0522014-09-19 10:34:07 -0700133 int64_t last_show_ms;
134 int64_t now_ms;
135 int64_t sleep_ms;
136 struct timespec sleep_spec;
137 int fd;
138 int num_written;
David Sodman8ef20062015-01-06 09:23:40 -0800139 image_t* image;
140 uint32_t duration;
David Sodmanbbcb0522014-09-19 10:34:07 -0700141
David Sodmanbbcb0522014-09-19 10:34:07 -0700142 /*
143 * First draw the actual splash screen
144 */
David Sodmanf0a925a2015-05-04 11:19:19 -0700145 splash_clear_screen(splash);
146 term_activate(splash->terminal);
147 last_show_ms = -1;
148 for (i = 0; i < splash->num_images; i++) {
149 image = splash->image_frames[i].image;
150 status = image_load_image_from_file(image);
151 if (status != 0) {
152 LOG(WARNING, "image_load_image_from_file failed: %d", status);
153 break;
David Sodman8ef20062015-01-06 09:23:40 -0800154 }
155
David Sodmanf0a925a2015-05-04 11:19:19 -0700156 now_ms = get_monotonic_time_ms();
157 if (last_show_ms > 0) {
158 if (splash->loop_start >= 0 && i >= splash->loop_start)
159 duration = splash->loop_duration;
160 else
161 duration = splash->image_frames[i].duration;
162 sleep_ms = duration - (now_ms - last_show_ms);
163 if (sleep_ms > 0) {
164 sleep_spec.tv_sec = sleep_ms / MS_PER_SEC;
165 sleep_spec.tv_nsec = (sleep_ms % MS_PER_SEC) * NS_PER_MS;
166 nanosleep(&sleep_spec, NULL);
167 }
168 }
169
170 now_ms = get_monotonic_time_ms();
171
172 if (i >= splash->loop_start) {
173 image_set_offset(image,
174 splash->loop_offset_x,
175 splash->loop_offset_y);
176 }
177
178 status = term_show_image(splash->terminal, image);
179 if (status != 0) {
180 LOG(WARNING, "term_show_image failed: %d", status);
181 break;
182 }
183 status = input_process(splash->terminal, 1);
184 if (status != 0) {
185 LOG(WARNING, "input_process failed: %d", status);
186 break;
187 }
188 last_show_ms = now_ms;
189
190 if ((splash->loop_start >= 0) &&
191 (splash->loop_start < splash->num_images)) {
192 if (i == splash->num_images - 1)
193 i = splash->loop_start - 1;
194 }
195
196 image_release(image);
197 }
198
199 for (i = 0; i < splash->num_images; i++) {
200 image_destroy(splash->image_frames[i].image);
201 }
202
203 input_set_current(NULL);
204
205 /*
206 * Now Chrome can take over
207 */
208 video_release(splash->video);
209 video_unlock(splash->video);
210
211 if (dbus != NULL) {
212 do {
213 *dbus = dbus_init();
214 usleep(DBUS_WAIT_DELAY);
215 } while (*dbus == NULL);
216 splash_set_dbus(splash, *dbus);
217 }
218
219 if (splash->devmode) {
David Sodman5c9afa72015-02-14 09:32:53 -0800220 /*
David Sodmanf0a925a2015-05-04 11:19:19 -0700221 * Now set drm_master_relax so that we can transfer drm_master between
222 * chrome and frecon
David Sodman5c9afa72015-02-14 09:32:53 -0800223 */
224 video_release(splash->video);
David Sodman8ef20062015-01-06 09:23:40 -0800225 video_unlock(splash->video);
David Sodman5c9afa72015-02-14 09:32:53 -0800226
David Sodman8ef20062015-01-06 09:23:40 -0800227 if (dbus != NULL) {
228 do {
229 *dbus = dbus_init();
230 usleep(DBUS_WAIT_DELAY);
231 } while (*dbus == NULL);
232 splash_set_dbus(splash, *dbus);
233 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700234 fd = open("/sys/kernel/debug/dri/drm_master_relax", O_WRONLY);
235 if (fd != -1) {
236 num_written = write(fd, "Y", 1);
237 close(fd);
David Sodmanbbcb0522014-09-19 10:34:07 -0700238
David Sodmanbbcb0522014-09-19 10:34:07 -0700239 /*
David Sodmanf0a925a2015-05-04 11:19:19 -0700240 * If we can't set drm_master relax, then transitions between chrome
241 * and frecon won't work. No point in having frecon hold any resources
David Sodmanbbcb0522014-09-19 10:34:07 -0700242 */
David Sodmanf0a925a2015-05-04 11:19:19 -0700243 if (num_written != 1) {
244 LOG(ERROR, "Unable to set drm_master_relax");
245 splash->devmode = false;
David Sodmanbbcb0522014-09-19 10:34:07 -0700246 }
David Sodmandd5b23e2015-02-18 21:36:38 -0800247 } else {
David Sodmanf0a925a2015-05-04 11:19:19 -0700248 LOG(ERROR, "unable to open drm_master_relax");
David Sodmanbbcb0522014-09-19 10:34:07 -0700249 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700250 } else {
251 /*
252 * Below, we will wait for Chrome to appear above the splash
253 * image. If we are not in dev mode, wait and then exit
254 */
255 sleep(MAX_SPLASH_WAITTIME);
256 exit(EXIT_SUCCESS);
David Sodmanbbcb0522014-09-19 10:34:07 -0700257 }
David Sodman003faed2014-11-03 09:02:10 -0800258
David Sodman8ef20062015-01-06 09:23:40 -0800259 if (splash->dbus) {
260 (void)dbus_method_call0(splash->dbus,
261 kLibCrosServiceName,
262 kLibCrosServicePath,
263 kLibCrosServiceInterface,
264 kTakeDisplayOwnership);
265 }
David Sodmanf348b0d2015-02-10 08:34:57 -0800266
267 /*
268 * Finally, wait until chrome has drawn on top of the splash. In dev mode,
269 * wait a few seconds for chrome to show up.
270 */
271 sleep(MAX_SPLASH_WAITTIME);
David Sodmanbbcb0522014-09-19 10:34:07 -0700272 return status;
273}
274
David Sodman8ef20062015-01-06 09:23:40 -0800275void splash_set_offset(splash_t* splash, int32_t x, int32_t y)
276{
277 if (splash) {
278 splash->offset_x = x;
279 splash->offset_y = y;
280 }
281}
282
David Sodmanbbcb0522014-09-19 10:34:07 -0700283void splash_set_dbus(splash_t* splash, dbus_t* dbus)
284{
David Sodman8ef20062015-01-06 09:23:40 -0800285 if (splash)
286 splash->dbus = dbus;
David Sodmanbbcb0522014-09-19 10:34:07 -0700287}
288
289void splash_set_devmode(splash_t* splash)
290{
David Sodman8ef20062015-01-06 09:23:40 -0800291 if (splash)
292 splash->devmode = true;
293}
294
295int splash_num_images(splash_t *splash)
296{
297 if (splash)
298 return splash->num_images;
299
300 return 0;
301}
302
303void splash_set_default_duration(splash_t* splash, uint32_t duration)
304{
305 if (splash)
306 splash->default_duration = duration;
307}
308
309void splash_set_loop_start(splash_t* splash, int32_t loop_start)
310{
311 if (splash)
312 splash->loop_start = loop_start;
313}
314
315void splash_set_loop_duration(splash_t* splash, uint32_t duration)
316{
317 if (splash)
318 splash->loop_duration = duration;
319}
320
321void splash_set_loop_offset(splash_t* splash, int32_t x, int32_t y)
322{
323 if (splash) {
324 splash->loop_offset_x = x;
325 splash->loop_offset_y = y;
326 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700327}
David Sodmanf0a925a2015-05-04 11:19:19 -0700328
329void splash_present_term_file(splash_t* splash)
330{
331 fprintf(stdout, "%s\n", term_get_ptsname(splash->terminal));
332}