A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 149 lines 4.6 kB view raw
1/*************************************************************************** 2* __________ __ ___. 3* Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7* \/ \/ \/ \/ \/ 8* $Id$ 9* 10* Copyright (C) 2010 by Thomas Martitz 11* 12* This program is free software; you can redistribute it and/or 13* modify it under the terms of the GNU General Public License 14* as published by the Free Software Foundation; either version 2 15* of the License, or (at your option) any later version. 16* 17* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18* KIND, either express or implied. 19* 20****************************************************************************/ 21 22 23#include "plugin.h" 24#include <setjmp.h> 25 26PLUGIN_HEADER 27 28/* 29 * EXIT_MAGIC magic, because 0 cannot be used due to setjmp() 30 * must be > 0 31 */ 32#define EXIT_MAGIC 0x0CDEBABE 33 34extern enum plugin_status plugin_start(const void*); 35#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 36extern unsigned char plugin_bss_start[]; 37extern unsigned char plugin_end_addr[]; 38#endif 39 40static jmp_buf __exit_env; 41/* only 1 atexit handler for now, chain in the exit handler if you need more */ 42static void (*atexit_handler)(void); 43 44int rb_atexit(void (*fn)(void)) 45{ 46 if (atexit_handler) 47 return -1; 48 atexit_handler = fn; 49 return 0; 50} 51 52void exit(int status) 53{ /* jump back in time to before starting the plugin */ 54 longjmp(__exit_env, status != 0 ? status : EXIT_MAGIC); 55} 56 57void _exit(int status) 58{ /* don't call exit handler */ 59 atexit_handler = NULL; 60 exit(status); 61} 62 63enum plugin_status plugin__start(const void *param) 64{ 65 int exit_ret; 66 enum plugin_status ret; 67 68#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 69 70/* IRAM must be copied before clearing the BSS ! */ 71#ifdef PLUGIN_USE_IRAM 72 extern char iramcopy[], iramstart[], iramend[], iedata[], iend[]; 73 size_t iram_size = iramend - iramstart; 74 size_t ibss_size = iend - iedata; 75 if (iram_size > 0 || ibss_size > 0) 76 { 77 /* We need to stop audio playback in order to use codec IRAM */ 78 rb->audio_stop(); 79 rb->memcpy(iramstart, iramcopy, iram_size); 80 rb->memset(iedata, 0, ibss_size); 81 /* make the icache (if it exists) up to date with the new code */ 82 rb->commit_discard_idcache(); 83 84 /* barrier to prevent reordering iram copy and BSS clearing, 85 * because the BSS segment alias the IRAM copy. 86 */ 87 asm volatile ("" ::: "memory"); 88 } 89#endif /* PLUGIN_USE_IRAM */ 90 91 /* zero out the bss section */ 92 rb->memset(plugin_bss_start, 0, plugin_end_addr - plugin_bss_start); 93 94 /* Some parts of bss may be used via a no-cache alias (at least 95 * portalplayer has this). If we don't clear the cache, those aliases 96 * may read garbage */ 97 rb->commit_dcache(); 98#endif 99 100 /* we come back here if exit() was called or the plugin returned normally */ 101 exit_ret = setjmp(__exit_env); 102 if (exit_ret == 0) 103 { /* start the plugin */ 104 ret = plugin_start(param); 105 } 106 else 107 { /* plugin exit via exit() */ 108 if (exit_ret == EXIT_MAGIC) 109 { /* exit(EXIT_SUCCESS) */ 110 ret = PLUGIN_OK; 111 } 112 else if (exit_ret < INTERNAL_PLUGIN_RETVAL_START) 113 { /* exit(EXIT_FAILURE) */ 114 ret = PLUGIN_ERROR; 115 } 116 else 117 { /* exit(PLUGIN_XXX) */ 118 ret = (enum plugin_status)exit_ret; 119 } 120 } 121 122 /* before finishing, call the exit handler if there was one */ 123 if (atexit_handler != NULL) 124 atexit_handler(); 125 126 return ret; 127} 128 129static void cleanup_wrapper(void *param) 130{ 131 (void)param; 132 if (atexit_handler) 133 atexit_handler(); 134} 135 136void exit_on_usb(int button) 137{ /* the default handler will call the exit handler before 138 * showing the usb screen; after that we don't want the exit handler 139 * to be called a second time, hence _exit() 140 * 141 * if not usb, then the handler will only be called if powering off 142 * if poweroff, the plugin doesn't want to run any further so exit as well*/ 143 long result = rb->default_event_handler_ex(button, cleanup_wrapper, NULL); 144 if (result == SYS_USB_CONNECTED) 145 _exit(PLUGIN_USB_CONNECTED); 146 else if (result == SYS_POWEROFF || result == SYS_REBOOT) 147 /* note: nobody actually pays attention to this exit code */ 148 _exit(PLUGIN_POWEROFF); 149}