@@ -68,8 +68,9 @@ uint16_t alt_launcher_fb_terminal_key(uint32_t mask, bool osd_button)
6868static pid_t s_pid = 0 ;
6969static int s_crash_count = 0 ;
7070static unsigned long s_respawn_timer = 0 ;
71+ static unsigned long s_tty_deadline = 0 ;
7172static unsigned long s_native_status_timer = 0 ;
72- static unsigned long s_native_fb_mode_timer = 0 ;
73+ static unsigned long s_native_crt_finish_timer = 0 ;
7374static bool s_gave_up = false ;
7475static bool s_init_pending = false ;
7576static bool s_native_crt = false ;
@@ -81,6 +82,8 @@ static const char s_tty_path[] = "/dev/tty2";
8182static const char s_fb_mode_path[] = " /sys/module/MiSTer_fb/parameters/mode" ;
8283static const char s_crt_state_file[] = " zaparoo_launcher_crt.bin" ;
8384static const char s_offsets_file[] = " zaparoo_video_offsets.bin" ;
85+ static char s_saved_fb_mode[64 ];
86+ static bool s_saved_fb_mode_valid = false ;
8487
8588static int8_t s_h_offset = 0 ;
8689static int8_t s_v_offset = 0 ;
@@ -134,9 +137,48 @@ static void set_launcher_fb_mode(int fmt, int rb, int width, int height, int str
134137 printf (" alt_launcher: fb mode set to %dx%d fmt=%d stride=%d\n " , width, height, fmt, stride);
135138}
136139
137- static void set_native_crt_fb_mode ( bool log = true )
140+ static void save_current_fb_mode ( void )
138141{
139- set_launcher_fb_mode (8888 , 1 , 320 , 240 , 1280 , log);
142+ if (s_saved_fb_mode_valid)
143+ return ;
144+
145+ FILE *fp = fopen (s_fb_mode_path, " rt" );
146+ if (!fp)
147+ {
148+ printf (" alt_launcher: unable to read fb mode: %s\n " , strerror (errno));
149+ return ;
150+ }
151+
152+ if (fgets (s_saved_fb_mode, sizeof (s_saved_fb_mode), fp))
153+ {
154+ size_t len = strlen (s_saved_fb_mode);
155+ while (len && (s_saved_fb_mode[len - 1 ] == ' \n ' || s_saved_fb_mode[len - 1 ] == ' \r ' ))
156+ s_saved_fb_mode[--len] = 0 ;
157+ s_saved_fb_mode_valid = len != 0 ;
158+ if (s_saved_fb_mode_valid)
159+ printf (" alt_launcher: saved fb mode '%s'\n " , s_saved_fb_mode);
160+ }
161+ fclose (fp);
162+ }
163+
164+ static void restore_saved_fb_mode (void )
165+ {
166+ if (!s_saved_fb_mode_valid)
167+ {
168+ set_launcher_fb_mode (8888 , 1 , 960 , 720 , 3840 );
169+ return ;
170+ }
171+
172+ FILE *fp = fopen (s_fb_mode_path, " wt" );
173+ if (!fp)
174+ {
175+ printf (" alt_launcher: unable to restore fb mode: %s\n " , strerror (errno));
176+ return ;
177+ }
178+
179+ fprintf (fp, " %s\n " , s_saved_fb_mode);
180+ fclose (fp);
181+ printf (" alt_launcher: restored fb mode '%s'\n " , s_saved_fb_mode);
140182}
141183
142184static void blank_native_crt_fb (void )
@@ -227,41 +269,33 @@ static void disable_native_crt_path(void)
227269 user_io_status_set (" [9]" , 0 );
228270 video_fb_enable (0 );
229271 set_vga_fb (0 );
230- set_launcher_fb_mode (8888 , 1 , 960 , 720 , 3840 );
272+ restore_saved_fb_mode ();
273+ s_tty_deadline = 0 ;
231274 s_native_status_timer = 0 ;
232- s_native_fb_mode_timer = 0 ;
275+ s_native_crt_finish_timer = 0 ;
233276}
234277
235- static void enable_native_crt_path (void )
278+ static void prepare_native_crt_path (void )
236279{
237280 set_vga_fb (0 );
238281 video_fb_enable (0 );
282+ save_current_fb_mode ();
283+ s_native_crt_finish_timer = GetTimer (1 );
284+ if (!s_native_crt_finish_timer) s_native_crt_finish_timer = 1 ;
285+ }
239286
240- // Double-write with a settle window so the kernel module's 320x240 layout
241- // is live before status[9] flips. Without this, the frontend renders for
242- // up to a second under stale dims (the post-fork retry timer used to be
243- // what eventually fixed the picture).
244- set_native_crt_fb_mode (false );
245- usleep (100000 );
246- set_native_crt_fb_mode ();
287+ static void finish_native_crt_path (void )
288+ {
289+ // Main_MiSTer does not program the launcher framebuffer mode. The
290+ // frontend owns its linuxfb `vmode`; this side only blanks the native DDR
291+ // scan-out buffer before status[9] routes the FPGA to it.
292+ s_native_crt_finish_timer = 0 ;
247293
248294 blank_native_crt_fb ();
249295
250296 user_io_status_set (" [9]" , 1 );
251297 s_native_status_timer = GetTimer (500 );
252298 if (!s_native_status_timer) s_native_status_timer = 1 ;
253- s_native_fb_mode_timer = GetTimer (1000 );
254- if (!s_native_fb_mode_timer) s_native_fb_mode_timer = 1 ;
255- }
256-
257- static void wait_launcher_tty_ready (pid_t pid)
258- {
259- for (int i = 0 ; i < 100 ; i++)
260- {
261- if (launcher_tty_ready (pid))
262- return ;
263- usleep (10000 );
264- }
265299}
266300
267301static void return_to_normal_mode (void )
@@ -282,6 +316,9 @@ static void reset_launcher_state(void)
282316{
283317 s_pid = 0 ;
284318 s_respawn_timer = 0 ;
319+ s_tty_deadline = 0 ;
320+ s_native_status_timer = 0 ;
321+ s_native_crt_finish_timer = 0 ;
285322 s_crash_count = 0 ;
286323 s_gave_up = false ;
287324 s_init_pending = false ;
@@ -337,34 +374,71 @@ static void release_launcher_video(void)
337374 }
338375}
339376
377+ static void exec_launcher_child (const char *path)
378+ {
379+ setenv (" LC_ALL" , " en_US.UTF-8" , 1 );
380+ setenv (" HOME" , " /root" , 1 );
381+
382+ cpu_set_t set;
383+ CPU_ZERO (&set);
384+ CPU_SET (0 , &set);
385+ sched_setaffinity (0 , sizeof (set), &set);
386+
387+ setsid ();
388+
389+ int tty_fd = open (s_tty_path, O_RDWR );
390+ if (tty_fd >= 0 )
391+ {
392+ ioctl (tty_fd, TIOCSCTTY , 0 );
393+ dup2 (tty_fd, STDIN_FILENO );
394+ dup2 (tty_fd, STDOUT_FILENO );
395+ dup2 (tty_fd, STDERR_FILENO );
396+ if (tty_fd > STDERR_FILENO )
397+ close (tty_fd);
398+ }
399+
400+ static const char clear[] = " \033 [0m\033 [?25l\033 [37m\033 [40m\033 [2J\033 [H" ;
401+ if (write (STDOUT_FILENO , clear, sizeof (clear) - 1 ) < 0 ) {}
402+
403+ if (s_native_crt)
404+ execl (path, path, " --crt" , NULL );
405+ else
406+ execl (path, path, NULL );
407+ _exit (1 );
408+ }
409+
410+ static void finalize_spawn (void )
411+ {
412+ s_tty_deadline = 0 ;
413+ video_chvt (s_vt);
414+ if (!s_native_crt)
415+ video_fb_enable (1 );
416+ else
417+ {
418+ input_switch (0 );
419+ user_io_status_set (" [9]" , 1 );
420+ }
421+
422+ // The frontend grabs input as soon as it starts. If the OSD is still
423+ // up (e.g. user toggled CRT mode or hit Reboot from System Settings),
424+ // it would trap input with no way to dismiss it — drop it now.
425+ if (menu_present ()) MenuHide ();
426+ }
427+
340428static void spawn (void )
341429{
342430 char path[2100 ];
343431 strncpy (path, getFullPath (s_launcher_path), sizeof (path) - 1 );
344432 path[sizeof (path) - 1 ] = ' \0 ' ;
345433
346- static const char cmd[] =
347- " #!/bin/bash\n "
348- " export LC_ALL=en_US.UTF-8\n "
349- " export HOME=/root\n "
350- " printf '\\ 033[0m\\ 033[?25l\\ 033[37m\\ 033[40m\\ 033[2J\\ 033[H'\n "
351- " if [ \" $ALT_LAUNCHER_CRT\" = \" 1\" ]; then\n "
352- " exec \" $ALT_LAUNCHER_PATH\" --crt\n "
353- " fi\n "
354- " exec \" $ALT_LAUNCHER_PATH\"\n " ;
355-
356- unlink (" /tmp/alt_launcher" );
357- if (!FileSave (" /tmp/alt_launcher" , (void *)cmd, strlen (cmd)))
358- return ;
359-
360434 user_io_osd_key_enable (0 );
361435 clear_launcher_tty ();
362436
363437 printf (" alt_launcher: native_crt=%d\n " , s_native_crt);
364438 if (s_native_crt)
365439 {
366- enable_native_crt_path ();
367- printf (" alt_launcher: native CRT path enabled \n " );
440+ prepare_native_crt_path ();
441+ printf (" alt_launcher: native CRT path prepared \n " );
368442 }
369443 else
370444 {
@@ -384,39 +458,23 @@ static void spawn(void)
384458 printf (" alt_launcher: spawned pid=%d path=%s\n " , s_pid, path);
385459 if (!s_pid)
386460 {
387- setenv (" ALT_LAUNCHER_PATH" , path, 1 );
388- setenv (" ALT_LAUNCHER_CRT" , s_native_crt ? " 1" : " 0" , 1 );
389- cpu_set_t set;
390- CPU_ZERO (&set);
391- CPU_SET (0 , &set);
392- sched_setaffinity (0 , sizeof (set), &set);
393- setsid ();
394- execl (" /sbin/agetty" , " /sbin/agetty" , " -a" , " root" , " -l" ,
395- " /tmp/alt_launcher" , " -i" , " --nohostname" , " -L" , s_tty, " linux" , NULL );
396- _exit (1 );
397- }
398-
399- wait_launcher_tty_ready (s_pid);
400- video_chvt (s_vt);
401- if (!s_native_crt)
402- video_fb_enable (1 );
403- else
404- {
405- input_switch (0 );
406- user_io_status_set (" [9]" , 1 );
461+ exec_launcher_child (path);
407462 }
408463
409- // The frontend grabs input as soon as it starts. If the OSD is still
410- // up (e.g. user toggled CRT mode or hit Reboot from System Settings),
411- // it would trap input with no way to dismiss it — drop it now.
412- if (menu_present ()) MenuHide ();
464+ s_tty_deadline = GetTimer (1000 );
465+ if (!s_tty_deadline) s_tty_deadline = 1 ;
413466}
414467
415468bool alt_launcher_active (void )
416469{
417470 return s_pid != 0 ;
418471}
419472
473+ bool alt_launcher_scheduler_sleep_enabled (void )
474+ {
475+ return s_pid || s_init_pending || s_respawn_timer || s_tty_deadline || s_native_crt_finish_timer;
476+ }
477+
420478bool alt_launcher_native_crt (void )
421479{
422480 return s_native_crt && s_pid != 0 ;
@@ -469,6 +527,7 @@ void alt_launcher_init(bool native_crt)
469527 return ;
470528 s_crash_count = 0 ;
471529 s_respawn_timer = 0 ;
530+ s_tty_deadline = 0 ;
472531 s_native_crt = native_crt;
473532 s_init_pending = true ;
474533}
@@ -486,6 +545,7 @@ void alt_launcher_prepare_for_script(void)
486545 wait_launcher_stopped (pid);
487546 user_io_osd_key_enable (1 );
488547 s_respawn_timer = 0 ;
548+ s_tty_deadline = 0 ;
489549 s_crash_count = 0 ;
490550 s_init_pending = false ;
491551 s_gave_up = false ;
@@ -514,23 +574,24 @@ void alt_launcher_poll(void)
514574{
515575 if (s_pid)
516576 {
577+ if (s_native_crt && s_native_crt_finish_timer && CheckTimer (s_native_crt_finish_timer))
578+ {
579+ finish_native_crt_path ();
580+ printf (" alt_launcher: native CRT path enabled\n " );
581+ }
582+
517583 if (s_native_crt && s_native_status_timer && CheckTimer (s_native_status_timer))
518584 {
519585 user_io_status_set (" [9]" , 1 );
520586 s_native_status_timer = GetTimer (500 );
521587 if (!s_native_status_timer) s_native_status_timer = 1 ;
522588 }
523589
524- if (s_native_crt && s_native_fb_mode_timer && CheckTimer (s_native_fb_mode_timer))
525- {
526- set_native_crt_fb_mode ();
527- s_native_fb_mode_timer = 0 ;
528- }
529-
530590 int status;
531591 if (waitpid (s_pid, &status, WNOHANG ) == s_pid)
532592 {
533593 s_pid = 0 ;
594+ s_tty_deadline = 0 ;
534595 user_io_osd_key_enable (1 );
535596 bool exited = WIFEXITED (status);
536597 int exit_status = exited ? WEXITSTATUS (status) : 0 ;
@@ -565,7 +626,11 @@ void alt_launcher_poll(void)
565626 s_crash_count = 0 ;
566627 s_respawn_timer = GetTimer (1000 );
567628 if (!s_respawn_timer) s_respawn_timer = 1 ;
629+ return ;
568630 }
631+
632+ if (s_tty_deadline && !s_native_crt_finish_timer && (launcher_tty_ready (s_pid) || CheckTimer (s_tty_deadline)))
633+ finalize_spawn ();
569634 return ;
570635 }
571636
0 commit comments