A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1#include "plugin.h"
2
3#include "fixedpoint.h"
4#include "lib/helper.h"
5#include "lib/pluginlib_exit.h"
6
7
8#include "SDL.h"
9#include "SDL_video.h"
10
11#ifdef COMBINED_SDL
12#error deprecated
13#endif
14
15/* SDL program */
16extern int my_main(int argc, char *argv[]);
17
18void *audiobuf = NULL;
19
20unsigned int sdl_thread_id, main_thread_id;
21
22bool printf_enabled = true;
23
24static void (*exit_cb)(void) = NULL;
25
26/* sets the exit handler presented to the program */
27void rbsdl_atexit(void (*cb)(void))
28{
29 if(exit_cb)
30 {
31 rb->splash(HZ, "WARNING: multiple exit handlers!");
32 }
33 exit_cb = cb;
34}
35
36/* called by program */
37void rb_exit(int rc)
38{
39 if(rb->thread_self() == main_thread_id) /* rockbox main thread */
40 exit(rc);
41 else
42 rb->thread_exit();
43}
44
45/* exit handler, called by rockbox */
46void cleanup(void)
47{
48 if(exit_cb)
49 exit_cb();
50
51 if(exit_cb != SDL_Quit)
52 SDL_Quit();
53
54#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) && !defined(RB_PROFILE)
55#define USE_TIMER
56#endif
57
58#ifdef USE_TIMER
59 /* stop timer callback if there is one, since the memory it
60 * resides in could be overwritten */
61 rb->timer_unregister();
62#endif
63
64 if(audiobuf)
65 memset(audiobuf, 0, 4); /* clear */
66
67 backlight_use_settings();
68
69#ifdef HAVE_ADJUSTABLE_CPU_FREQ
70 rb->cpu_boost(false);
71#endif
72}
73
74static long main_stack[1024 * 1024 / 4]; /* ie 1 MB */
75
76int (*main_fn)(int argc, char *argv[]);
77int prog_idx;
78static void main_thread(void)
79{
80 char *fallback[] = { "/blah", NULL };
81
82#ifdef COMBINED_SDL
83 char **argv = programs[prog_idx].argv ? programs[prog_idx].argv : fallback;
84 int argc = programs[prog_idx].argv ? programs[prog_idx].argc : 1;
85#else
86 char **argv = fallback;
87 int argc = 1;
88#endif
89
90 int rc = main_fn(argc, argv);
91 if(rc != 0)
92 rb->splash(HZ * 2, SDL_GetError());
93
94 rb->thread_exit();
95}
96
97#if defined(CPU_ARM) && !defined(SIMULATOR)
98#define CR_M (1 << 0) /* MMU enable */
99#define CR_A (1 << 1) /* Alignment abort enable */
100#define CR_C (1 << 2) /* Dcache enable */
101#define CR_W (1 << 3) /* Write buffer enable */
102#define CR_P (1 << 4) /* 32-bit exception handler */
103#define CR_D (1 << 5) /* 32-bit data address range */
104#define CR_L (1 << 6) /* Implementation defined */
105#define CR_B (1 << 7) /* Big endian */
106#define CR_S (1 << 8) /* System MMU protection */
107#define CR_R (1 << 9) /* ROM MMU protection */
108#define CR_F (1 << 10) /* Implementation defined */
109#define CR_Z (1 << 11) /* Implementation defined */
110#define CR_I (1 << 12) /* Icache enable */
111#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */
112#define CR_RR (1 << 14) /* Round Robin cache replacement */
113#define CR_L4 (1 << 15) /* LDR pc can set T bit */
114#define CR_DT (1 << 16)
115#ifdef CONFIG_MMU
116#define CR_HA (1 << 17) /* Hardware management of Access Flag */
117#else
118#define CR_BR (1 << 17) /* MPU Background region enable (PMSA) */
119#endif
120#define CR_IT (1 << 18)
121#define CR_ST (1 << 19)
122#define CR_FI (1 << 21) /* Fast interrupt (lower latency mode) */
123#define CR_U (1 << 22) /* Unaligned access operation */
124#define CR_XP (1 << 23) /* Extended page tables */
125#define CR_VE (1 << 24) /* Vectored interrupts */
126#define CR_EE (1 << 25) /* Exception (Big) Endian */
127#define CR_TRE (1 << 28) /* TEX remap enable */
128#define CR_AFE (1 << 29) /* Access flag enable */
129#define CR_TE (1 << 30) /* Thumb exception enable */
130
131#define __LINUX_ARM_ARCH__ ARM_ARCH
132
133#if __LINUX_ARM_ARCH__ >= 7
134#define isb(option) __asm__ __volatile__ ("isb " #option : : : "memory")
135#define dsb(option) __asm__ __volatile__ ("dsb " #option : : : "memory")
136#define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory")
137#elif defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ == 6
138#define isb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
139 : : "r" (0) : "memory")
140#define dsb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
141 : : "r" (0) : "memory")
142#define dmb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
143 : : "r" (0) : "memory")
144#elif defined(CONFIG_CPU_FA526)
145#define isb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
146 : : "r" (0) : "memory")
147#define dsb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
148 : : "r" (0) : "memory")
149#define dmb(x) __asm__ __volatile__ ("" : : : "memory")
150#else
151#define isb(x) __asm__ __volatile__ ("" : : : "memory")
152#define dsb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
153 : : "r" (0) : "memory")
154#define dmb(x) __asm__ __volatile__ ("" : : : "memory")
155#endif
156
157static inline unsigned long get_cr(void)
158{
159 unsigned long val;
160 asm("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val) : : "cc");
161 return val;
162}
163
164static inline void set_cr(unsigned long val)
165{
166 asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR"
167 : : "r" (val) : "cc");
168 isb();
169}
170#endif
171
172enum plugin_status plugin_start(const void *param)
173{
174 (void) param;
175
176#if defined(CPU_ARM) && !defined(SIMULATOR) && (ARM_ARCH >= 5)
177 /* (don't) set alignment trap. Will generate a data abort
178 * exception on ARM. */
179// set_cr(get_cr() | CR_A);
180#endif
181
182#if 0
183 char c = *((char*)NULL);
184
185 /* test alignment trap */
186 unsigned int x = 0x12345678;
187 char *p = ((char*)&x) + 1;
188 unsigned short *p2 = (unsigned short*)p;
189 rb->splashf(HZ, "%04x, %02x%02x", *p2, *(p+1), *p);
190#endif
191
192 /* don't confuse this with the main SDL thread! */
193 main_thread_id = rb->thread_self();
194
195 /* we always use the audio buffer */
196 size_t sz;
197 audiobuf = rb->plugin_get_audio_buffer(&sz);
198#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
199 /* We are loaded as an overlay towards the end of the audio
200 * buffer. We must take care not to overwrite ourselves. */
201 if ((uintptr_t)audiobuf < (uintptr_t)plugin_start_addr)
202 {
203 uint32_t tmp_size = (uintptr_t)plugin_start_addr - (uintptr_t)audiobuf;
204 sz = MIN(sz, tmp_size);
205 }
206#endif
207
208 /* wipe sig */
209 rb->memset(audiobuf, 0, sz);
210 if(init_memory_pool(sz, audiobuf) == (size_t) -1)
211 {
212 rb->splashf(HZ*2, "TLSF init failed!");
213 return PLUGIN_ERROR;
214 }
215
216 main_fn = my_main;
217
218#ifdef HAVE_ADJUSTABLE_CPU_FREQ
219 rb->cpu_boost(true);
220#endif
221
222 backlight_ignore_timeout();
223
224 /* set the real exit handler */
225#undef rb_atexit
226 rb_atexit(cleanup);
227
228 /* make a new thread to use a bigger stack and higher priority than otherwise accessible */
229 sdl_thread_id = rb->create_thread(main_thread, main_stack,
230 sizeof(main_stack), 0, "sdl_main"
231 IF_PRIO(, PRIORITY_USER_INTERFACE) // we need other threads still
232 IF_COP(, CPU));
233 rb->thread_wait(sdl_thread_id);
234
235 rb->sleep(HZ); /* wait a second in case there's an error message on screen */
236
237 return PLUGIN_OK;
238}