1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
diff --git a/firmware/SOURCES b/firmware/SOURCES
index a592ad1..eb0dd97 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -37,7 +37,9 @@ target/hosted/sdl/lcd-remote-bitmap.c
 #endif
 target/hosted/sdl/lcd-sdl.c
 target/hosted/sdl/system-sdl.c
+#if ((CONFIG_PLATFORM & PLATFORM_MAEMO) == 0)
 target/hosted/sdl/thread-sdl.c
+#endif
 target/hosted/sdl/timer-sdl.c
 #ifdef HAVE_TOUCHSCREEN
 target/hosted/sdl/key_to_touch-sdl.c
@@ -50,6 +52,7 @@ target/hosted/sdl/app/button-application.c
 /* Maemo specific files */
 #if (CONFIG_PLATFORM & PLATFORM_MAEMO)
 target/hosted/maemo/maemo-osso.c
+thread.c
 #endif

 /* Standard library */
diff --git a/firmware/export/thread.h b/firmware/export/thread.h
index 87c2d2d..c1e8838 100644
--- a/firmware/export/thread.h
+++ b/firmware/export/thread.h
@@ -92,7 +92,7 @@
 #endif


-#if (CONFIG_PLATFORM & (PLATFORM_NATIVE|PLATFORM_ANDROID))
+#if (CONFIG_PLATFORM & (PLATFORM_NATIVE|PLATFORM_ANDROID|PLATFORM_MAEMO))
 /* Need to keep structures inside the header file because debug_menu
  * needs them. */
 #ifdef CPU_COLDFIRE
@@ -112,7 +112,7 @@ struct regs
     uint32_t pr;    /*    32 - Procedure register */
     uint32_t start; /*    36 - Thread start address, or NULL when started */
 };
-#elif defined(CPU_ARM) || (CONFIG_PLATFORM & PLATFORM_ANDROID)
+#elif defined(CPU_ARM) || (CONFIG_PLATFORM & (PLATFORM_ANDROID|PLATFORM_MAEMO))
 struct regs
 {
     uint32_t r[8];  /*  0-28 - Registers r4-r11 */
diff --git a/firmware/target/hosted/maemo/thread-maemo-arm.c b/firmware/target/hosted/maemo/thread-maemo-arm.c
new file mode 100644
index 0000000..a482795
--- /dev/null
+++ b/firmware/target/hosted/maemo/thread-maemo-arm.c
@@ -0,0 +1,98 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2005 by Thom Johansen
+ * Copyright (C) 2010 by Thomas Martitz (Android-suitable core_sleep())
+ *
+ * Generic ARM threading support
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <system.h>
+/*---------------------------------------------------------------------------
+ * Start the thread running and terminate it if it returns
+ *---------------------------------------------------------------------------
+ */
+static void __attribute__((naked,used)) start_thread(void)
+{
+    /* r0 = context */
+    asm volatile (
+        "ldr    sp, [r0, #32]            \n" /* Load initial sp */
+        "ldr    r4, [r0, #40]            \n" /* start in r4 since it's non-volatile */
+        "mov    r1, #0                   \n" /* Mark thread as running */
+        "str    r1, [r0, #40]            \n"
+        "mov    lr, pc                   \n" /* Call thread function */
+        "bx     r4                       \n"
+    ); /* No clobber list - new thread doesn't care */
+    thread_exit();
+}
+
+/* For startup, place context pointer in r4 slot, start_thread pointer in r5
+ * slot, and thread function pointer in context.start. See load_context for
+ * what happens when thread is initially going to run. */
+#define THREAD_STARTUP_INIT(core, thread, function) \
+    ({ (thread)->context.r[0] = (uint32_t)&(thread)->context,  \
+       (thread)->context.r[1] = (uint32_t)start_thread, \
+       (thread)->context.start = (uint32_t)function; })
+
+
+/*---------------------------------------------------------------------------
+ * Store non-volatile context.
+ *---------------------------------------------------------------------------
+ */
+static inline void store_context(void* addr)
+{
+    asm volatile(
+        "stmia  %0, { r4-r11, sp, lr } \n"
+        : : "r" (addr)
+    );
+}
+
+/*---------------------------------------------------------------------------
+ * Load non-volatile context.
+ *---------------------------------------------------------------------------
+ */
+static inline void load_context(const void* addr)
+{
+    asm volatile(
+        "ldr     r0, [%0, #40]          \n" /* Load start pointer */
+        "cmp     r0, #0                 \n" /* Check for NULL */
+
+        /* If not already running, jump to start */
+        "ldmneia %0, { r0, pc }         \n"
+        "ldmia   %0, { r4-r11, sp, lr } \n" /* Load regs r4 to r14 from context */
+        : : "r" (addr) : "r0" /* only! */
+    );
+}
+
+/*
+ * this core sleep suspends the OS thread rockbox runs under, which greatly
+ * reduces cpu usage (~100% to <10%)
+ *
+ * it returns when the RockboxTimer notified us, i.e. at each tick
+ * (after it called the tick tasks)
+ *
+ * wait_for_interrupt is implemented in kernel-android.c
+ **/
+
+static inline void core_sleep(void)
+{
+    void wait_for_interrupt(void);
+    wait_for_interrupt();
+}
+
+
diff --git a/firmware/target/hosted/sdl/kernel-sdl.c b/firmware/target/hosted/sdl/kernel-sdl.c
index c4d4ee2..15934ee 100644
--- a/firmware/target/hosted/sdl/kernel-sdl.c
+++ b/firmware/target/hosted/sdl/kernel-sdl.c
@@ -34,6 +34,12 @@
 static SDL_TimerID tick_timer_id;
 long start_tick;

+#ifndef HAVE_SDL_THREADS
+/* for the wait_for_interrupt function */
+static bool do_exit;
+static SDL_cond *wfi_cond;
+static SDL_mutex *wfi_mutex;
+#endif
 /* Condition to signal that "interrupts" may proceed */
 static SDL_cond *sim_thread_cond;
 /* Mutex to serialize changing levels and exclude other threads while
@@ -89,6 +95,9 @@ void sim_exit_irq_handler(void)

     status_reg = 0;
     SDL_UnlockMutex(sim_irq_mtx);
+#ifndef HAVE_SDL_THREADS
+    SDL_CondSignal(wfi_cond);
+#endif
 }

 static bool sim_kernel_init(void)
@@ -106,15 +115,33 @@ static bool sim_kernel_init(void)
         panicf("Cannot create sim_thread_cond\n");
         return false;
     }
-
+#ifndef HAVE_SDL_THREADS
+    wfi_cond = SDL_CreateCond();
+    if (wfi_cond == NULL)
+    {
+        panicf("Cannot create wfi\n");
+        return false;
+    }
+    wfi_mutex = SDL_CreateMutex();
+    if (wfi_mutex == NULL)
+    {
+        panicf("Cannot create wfi mutex\n");
+        return false;
+    }
+#endif
     return true;
 }

 void sim_kernel_shutdown(void)
 {
+    disable_irq();
     SDL_RemoveTimer(tick_timer_id);
     SDL_DestroyMutex(sim_irq_mtx);
     SDL_DestroyCond(sim_thread_cond);
+#ifndef HAVE_SDL_THREADS
+    do_exit = true;
+    SDL_CondSignal(wfi_cond);
+#endif
 }

 Uint32 tick_timer(Uint32 interval, void *param)
@@ -159,4 +186,21 @@ void tick_start(unsigned int interval_in_ms)
     }

     tick_timer_id = SDL_AddTimer(interval_in_ms, tick_timer, NULL);
+#ifndef HAVE_SDL_THREADS
+    SDL_LockMutex(wfi_mutex);
+#endif
+}
+
+#ifndef HAVE_SDL_THREADS
+void wait_for_interrupt(void)
+{
+    SDL_CondWait(wfi_cond, wfi_mutex);
+    if (UNLIKELY(do_exit))
+    {
+        SDL_DestroyCond(wfi_cond);
+        SDL_UnlockMutex(wfi_mutex);
+        SDL_DestroyMutex(wfi_mutex);
+        sim_do_exit();
+    }
 }
+#endif
diff --git a/firmware/target/hosted/sdl/system-sdl.c b/firmware/target/hosted/sdl/system-sdl.c
index 4c56cf3..5d9205d 100644
--- a/firmware/target/hosted/sdl/system-sdl.c
+++ b/firmware/target/hosted/sdl/system-sdl.c
@@ -175,7 +175,9 @@ static int sdl_event_thread(void * param)

     /* Order here is relevent to prevent deadlocks and use of destroyed
        sync primitives by kernel threads */
-    sim_thread_shutdown();
+#ifdef HAVE_SDL_THREADS
+    sim_thread_shutdown(); /* not needed for native threads */
+#endif
     sim_kernel_shutdown();

     return 0;
@@ -190,9 +192,13 @@ void sim_do_exit(void)
     exit(EXIT_SUCCESS);
 }

+uintptr_t *stackbegin;
+uintptr_t *stackend;
 void system_init(void)
 {
     SDL_sem *s;
+    /* fake stack, OS manages size (and growth) */
+    stackbegin = stackend = (uintptr_t*)&s;

 #if (CONFIG_PLATFORM & PLATFORM_MAEMO)
     // Make glib thread safe
@@ -215,14 +221,19 @@ void system_init(void)
     SDL_DestroySemaphore(s);
 }

-void system_exception_wait(void)
+
+void system_reboot(void)
 {
+#ifdef HAVE_SDL_THREADS
     sim_thread_exception_wait();
+#else
+    sim_do_exit();
+#endif
 }

-void system_reboot(void)
+void system_exception_wait(void)
 {
-    sim_thread_exception_wait();
+    system_reboot();
 }


diff --git a/firmware/thread.c b/firmware/thread.c
index 655af1a..84370b7 100644
--- a/firmware/thread.c
+++ b/firmware/thread.c
@@ -178,6 +178,8 @@ void switch_thread(void)
  */
 #if defined(ANDROID)
 #include "thread-android-arm.c"
+#elif (CONFIG_PLATFORM & PLATFORM_MAEMO)
+#include "thread-maemo-arm.c"
 #elif defined(CPU_ARM)
 #include "thread-arm.c"
 #if defined (CPU_PP)
diff --git a/uisimulator/common/io.c b/uisimulator/common/io.c
index 56abf4b..756b956 100644
--- a/uisimulator/common/io.c
+++ b/uisimulator/common/io.c
@@ -46,9 +46,12 @@
 #endif

 #include <fcntl.h>
-#include <SDL.h>
-#include <SDL_thread.h>
+#ifdef HAVE_SDL_THREADS
 #include "thread-sdl.h"
+#else
+#define sim_thread_unlock() NULL
+#define sim_thread_lock(a)
+#endif
 #include "thread.h"
 #include "kernel.h"
 #include "debug.h"