diff options
36 files changed, 829 insertions, 408 deletions
diff --git a/apps/codecs.c b/apps/codecs.c index addb8b5e40..b4b8c9833a 100644 --- a/apps/codecs.c +++ b/apps/codecs.c | |||
@@ -123,7 +123,7 @@ struct codec_api ci = { | |||
123 | ¤t_tick, | 123 | ¤t_tick, |
124 | default_event_handler, | 124 | default_event_handler, |
125 | default_event_handler_ex, | 125 | default_event_handler_ex, |
126 | create_thread, | 126 | create_thread_on_core, |
127 | remove_thread, | 127 | remove_thread, |
128 | reset_poweroff_timer, | 128 | reset_poweroff_timer, |
129 | #ifndef SIMULATOR | 129 | #ifndef SIMULATOR |
diff --git a/apps/codecs.h b/apps/codecs.h index dde376d73c..96804a889b 100644 --- a/apps/codecs.h +++ b/apps/codecs.h | |||
@@ -196,8 +196,10 @@ struct codec_api { | |||
196 | long* current_tick; | 196 | long* current_tick; |
197 | long (*default_event_handler)(long event); | 197 | long (*default_event_handler)(long event); |
198 | long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); | 198 | long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); |
199 | int (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name); | 199 | struct thread_entry* (*create_thread)(unsigned int core, void (*function)(void), |
200 | void (*remove_thread)(int threadnum); | 200 | void* stack, int stack_size, const char *name |
201 | IF_PRIO(, int priority)); | ||
202 | void (*remove_thread)(struct thread_entry *thread); | ||
201 | void (*reset_poweroff_timer)(void); | 203 | void (*reset_poweroff_timer)(void); |
202 | #ifndef SIMULATOR | 204 | #ifndef SIMULATOR |
203 | int (*system_memory_guard)(int newmode); | 205 | int (*system_memory_guard)(int newmode); |
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 60f405ae50..bda5a5c4f0 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c | |||
@@ -80,13 +80,27 @@ extern char ata_device; | |||
80 | extern int ata_io_address; | 80 | extern int ata_io_address; |
81 | extern struct core_entry cores[NUM_CORES]; | 81 | extern struct core_entry cores[NUM_CORES]; |
82 | 82 | ||
83 | char thread_status_char(int status) | ||
84 | { | ||
85 | switch (status) | ||
86 | { | ||
87 | case STATE_RUNNING : return 'R'; | ||
88 | case STATE_BLOCKED : return 'B'; | ||
89 | case STATE_SLEEPING : return 'S'; | ||
90 | case STATE_BLOCKED_W_TMO: return 'T'; | ||
91 | } | ||
92 | |||
93 | return '?'; | ||
94 | } | ||
83 | #ifdef HAVE_LCD_BITMAP | 95 | #ifdef HAVE_LCD_BITMAP |
84 | /* Test code!!! */ | 96 | /* Test code!!! */ |
85 | bool dbg_os(void) | 97 | bool dbg_os(void) |
86 | { | 98 | { |
99 | struct thread_entry *thread; | ||
87 | char buf[32]; | 100 | char buf[32]; |
88 | int i; | 101 | int i; |
89 | int usage; | 102 | int usage; |
103 | int status; | ||
90 | #if NUM_CORES > 1 | 104 | #if NUM_CORES > 1 |
91 | unsigned int core; | 105 | unsigned int core; |
92 | int line; | 106 | int line; |
@@ -98,24 +112,54 @@ bool dbg_os(void) | |||
98 | 112 | ||
99 | while(1) | 113 | while(1) |
100 | { | 114 | { |
115 | #if 0 /* Enable to simulate UI lag. */ | ||
116 | int _x; | ||
117 | for (_x = 0; _x < 1000000L; _x++) ; | ||
118 | #endif | ||
101 | #if NUM_CORES > 1 | 119 | #if NUM_CORES > 1 |
102 | lcd_puts(0, 0, "Core and stack usage:"); | 120 | lcd_puts(0, 0, "Core and stack usage:"); |
103 | line = 0; | 121 | line = 0; |
104 | for(core = 0; core < NUM_CORES; core++) | 122 | for(core = 0; core < NUM_CORES; core++) |
105 | { | 123 | { |
106 | for(i = 0; i < num_threads[core]; i++) | 124 | for(i = 0; i < MAXTHREADS; i++) |
107 | { | 125 | { |
108 | usage = thread_stack_usage_on_core(core, i); | 126 | thread = &cores[core].threads[i]; |
109 | snprintf(buf, 32, "(%d) %s: %d%%", core, thread_name[core][i], usage); | 127 | if (thread->name == NULL) |
128 | continue; | ||
129 | |||
130 | usage = thread_stack_usage(thread); | ||
131 | status = thread_get_status(thread); | ||
132 | |||
133 | snprintf(buf, 32, "(%d) %c%c %d %s: %d%%", core, | ||
134 | (status == STATE_RUNNING) ? '*' : ' ', | ||
135 | thread_status_char(status), | ||
136 | cores[CURRENT_CORE].threads[i].priority, | ||
137 | cores[core].threads[i].name, usage); | ||
110 | lcd_puts(0, ++line, buf); | 138 | lcd_puts(0, ++line, buf); |
111 | } | 139 | } |
112 | } | 140 | } |
113 | #else | 141 | #else |
114 | lcd_puts(0, 0, "Stack usage:"); | 142 | lcd_puts(0, 0, "Stack usage:"); |
115 | for(i = 0; i < cores[CURRENT_CORE].num_threads;i++) | 143 | for(i = 0; i < MAXTHREADS; i++) |
116 | { | 144 | { |
117 | usage = thread_stack_usage(i); | 145 | thread = &cores[CURRENT_CORE].threads[i]; |
118 | snprintf(buf, 32, "%s: %d%%", cores[CURRENT_CORE].threads[i].name, usage); | 146 | if (thread->name == NULL) |
147 | continue; | ||
148 | |||
149 | usage = thread_stack_usage(thread); | ||
150 | status = thread_get_status(thread); | ||
151 | # ifdef HAVE_PRIORITY_SCHEDULING | ||
152 | snprintf(buf, 32, "%c%c %d %s: %d%%", | ||
153 | (status == STATE_RUNNING) ? '*' : ' ', | ||
154 | thread_status_char(status), | ||
155 | cores[CURRENT_CORE].threads[i].priority, | ||
156 | cores[CURRENT_CORE].threads[i].name, usage); | ||
157 | # else | ||
158 | snprintf(buf, 32, "%c%c %s: %d%%", | ||
159 | (status == STATE_RUNNING) ? '*' : ' ', | ||
160 | (status == STATE_BLOCKED) ? 'B' : ' ', | ||
161 | cores[CURRENT_CORE].threads[i].name, usage); | ||
162 | # endif | ||
119 | lcd_puts(0, 1+i, buf); | 163 | lcd_puts(0, 1+i, buf); |
120 | } | 164 | } |
121 | #endif | 165 | #endif |
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index b18d411db6..f8fd2af82a 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c | |||
@@ -35,9 +35,10 @@ | |||
35 | #include "settings.h" | 35 | #include "settings.h" |
36 | #include "audio.h" | 36 | #include "audio.h" |
37 | #include "dsp.h" | 37 | #include "dsp.h" |
38 | #include "thread.h" | ||
38 | 39 | ||
39 | /* 1.5s low mark */ | 40 | /* Keep watermark high for iPods at least (2s) */ |
40 | #define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 6) | 41 | #define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 8) |
41 | 42 | ||
42 | /* Structure we can use to queue pcm chunks in memory to be played | 43 | /* Structure we can use to queue pcm chunks in memory to be played |
43 | * by the driver code. */ | 44 | * by the driver code. */ |
@@ -94,6 +95,8 @@ static size_t pcmbuf_mix_sample IDATA_ATTR; | |||
94 | static bool low_latency_mode = false; | 95 | static bool low_latency_mode = false; |
95 | static bool pcmbuf_flush; | 96 | static bool pcmbuf_flush; |
96 | 97 | ||
98 | extern struct thread_entry *codec_thread_p; | ||
99 | |||
97 | /* Helpful macros for use in conditionals this assumes some of the above | 100 | /* Helpful macros for use in conditionals this assumes some of the above |
98 | * static variable names */ | 101 | * static variable names */ |
99 | #define NEED_FLUSH(position) \ | 102 | #define NEED_FLUSH(position) \ |
@@ -109,14 +112,37 @@ static bool pcmbuf_flush_fillpos(void); | |||
109 | void pcmbuf_boost(bool state) | 112 | void pcmbuf_boost(bool state) |
110 | { | 113 | { |
111 | static bool boost_state = false; | 114 | static bool boost_state = false; |
112 | 115 | #ifdef HAVE_PRIORITY_SCHEDULING | |
116 | static bool priority_modified = false; | ||
117 | #endif | ||
118 | |||
113 | if (crossfade_init || crossfade_active) | 119 | if (crossfade_init || crossfade_active) |
114 | return; | 120 | return; |
115 | 121 | ||
116 | if (state != boost_state) { | 122 | if (state != boost_state) |
123 | { | ||
117 | cpu_boost(state); | 124 | cpu_boost(state); |
118 | boost_state = state; | 125 | boost_state = state; |
119 | } | 126 | } |
127 | |||
128 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
129 | if (state && LOW_DATA(2) && pcm_is_playing()) | ||
130 | { | ||
131 | if (!priority_modified) | ||
132 | { | ||
133 | /* Buffer is critically low so override UI priority. */ | ||
134 | priority_modified = true; | ||
135 | thread_set_priority(codec_thread_p, PRIORITY_REALTIME); | ||
136 | } | ||
137 | } | ||
138 | else if (priority_modified) | ||
139 | { | ||
140 | /* Set back the original priority. */ | ||
141 | thread_set_priority(codec_thread_p, PRIORITY_PLAYBACK); | ||
142 | priority_modified = false; | ||
143 | } | ||
144 | |||
145 | #endif | ||
120 | } | 146 | } |
121 | #endif | 147 | #endif |
122 | 148 | ||
@@ -244,7 +270,9 @@ static void pcmbuf_under_watermark(void) | |||
244 | pcmbuf_boost(true); | 270 | pcmbuf_boost(true); |
245 | /* Disable crossfade if < .5s of audio */ | 271 | /* Disable crossfade if < .5s of audio */ |
246 | if (LOW_DATA(2)) | 272 | if (LOW_DATA(2)) |
273 | { | ||
247 | crossfade_active = false; | 274 | crossfade_active = false; |
275 | } | ||
248 | } | 276 | } |
249 | 277 | ||
250 | void pcmbuf_set_event_handler(void (*event_handler)(void)) | 278 | void pcmbuf_set_event_handler(void (*event_handler)(void)) |
@@ -270,8 +298,8 @@ bool pcmbuf_is_lowdata(void) | |||
270 | crossfade_init || crossfade_active) | 298 | crossfade_init || crossfade_active) |
271 | return false; | 299 | return false; |
272 | 300 | ||
273 | /* 0.5 seconds of buffer is low data */ | 301 | /* 1 seconds of buffer is low data */ |
274 | return LOW_DATA(2); | 302 | return LOW_DATA(4); |
275 | } | 303 | } |
276 | 304 | ||
277 | /* Amount of bytes left in the buffer. */ | 305 | /* Amount of bytes left in the buffer. */ |
@@ -443,7 +471,7 @@ static bool pcmbuf_flush_fillpos(void) | |||
443 | pcmbuf_play_start(); | 471 | pcmbuf_play_start(); |
444 | } | 472 | } |
445 | /* Let approximately one chunk of data playback */ | 473 | /* Let approximately one chunk of data playback */ |
446 | sleep(PCMBUF_TARGET_CHUNK/(NATIVE_FREQUENCY * 4) / 5); | 474 | sleep(HZ*PCMBUF_TARGET_CHUNK/(NATIVE_FREQUENCY*4)); |
447 | } | 475 | } |
448 | pcmbuf_add_chunk(); | 476 | pcmbuf_add_chunk(); |
449 | return true; | 477 | return true; |
diff --git a/apps/playback.c b/apps/playback.c index 352c99b390..33667cc656 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -176,7 +176,7 @@ static char *voicebuf; | |||
176 | static size_t voice_remaining; | 176 | static size_t voice_remaining; |
177 | static bool voice_is_playing; | 177 | static bool voice_is_playing; |
178 | static void (*voice_getmore)(unsigned char** start, int* size); | 178 | static void (*voice_getmore)(unsigned char** start, int* size); |
179 | static int voice_thread_num = -1; | 179 | static struct thread_entry *voice_thread_p = NULL; |
180 | 180 | ||
181 | /* Is file buffer currently being refilled? */ | 181 | /* Is file buffer currently being refilled? */ |
182 | static volatile bool filling IDATA_ATTR; | 182 | static volatile bool filling IDATA_ATTR; |
@@ -267,6 +267,8 @@ static struct event_queue codec_queue; | |||
267 | static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] | 267 | static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] |
268 | IBSS_ATTR; | 268 | IBSS_ATTR; |
269 | static const char codec_thread_name[] = "codec"; | 269 | static const char codec_thread_name[] = "codec"; |
270 | /* For modifying thread priority later. */ | ||
271 | struct thread_entry *codec_thread_p; | ||
270 | 272 | ||
271 | /* Voice thread */ | 273 | /* Voice thread */ |
272 | static struct event_queue voice_queue; | 274 | static struct event_queue voice_queue; |
@@ -628,13 +630,13 @@ void audio_preinit(void) | |||
628 | 630 | ||
629 | mutex_init(&mutex_codecthread); | 631 | mutex_init(&mutex_codecthread); |
630 | 632 | ||
631 | queue_init(&audio_queue); | 633 | queue_init(&audio_queue, true); |
632 | queue_init(&codec_queue); | 634 | queue_init(&codec_queue, true); |
633 | /* clear, not init to create a private queue */ | 635 | /* create a private queue */ |
634 | queue_clear(&codec_callback_queue); | 636 | queue_init(&codec_callback_queue, false); |
635 | 637 | ||
636 | create_thread(audio_thread, audio_stack, sizeof(audio_stack), | 638 | create_thread(audio_thread, audio_stack, sizeof(audio_stack), |
637 | audio_thread_name); | 639 | audio_thread_name IF_PRIO(, PRIORITY_BUFFERING)); |
638 | } | 640 | } |
639 | 641 | ||
640 | void audio_init(void) | 642 | void audio_init(void) |
@@ -648,14 +650,14 @@ void voice_init(void) | |||
648 | if (!filebuf) | 650 | if (!filebuf) |
649 | return; /* Audio buffers not yet set up */ | 651 | return; /* Audio buffers not yet set up */ |
650 | 652 | ||
651 | if (voice_thread_num >= 0) | 653 | if (voice_thread_p) |
652 | { | 654 | { |
653 | logf("Terminating voice codec"); | 655 | logf("Terminating voice codec"); |
654 | remove_thread(voice_thread_num); | 656 | remove_thread(voice_thread_p); |
655 | if (current_codec == CODEC_IDX_VOICE) | 657 | if (current_codec == CODEC_IDX_VOICE) |
656 | mutex_unlock(&mutex_codecthread); | 658 | mutex_unlock(&mutex_codecthread); |
657 | queue_delete(&voice_queue); | 659 | queue_delete(&voice_queue); |
658 | voice_thread_num = -1; | 660 | voice_thread_p = NULL; |
659 | voice_codec_loaded = false; | 661 | voice_codec_loaded = false; |
660 | } | 662 | } |
661 | 663 | ||
@@ -663,9 +665,10 @@ void voice_init(void) | |||
663 | return; | 665 | return; |
664 | 666 | ||
665 | logf("Starting voice codec"); | 667 | logf("Starting voice codec"); |
666 | queue_init(&voice_queue); | 668 | queue_init(&voice_queue, true); |
667 | voice_thread_num = create_thread(voice_thread, voice_stack, | 669 | voice_thread_p = create_thread(voice_thread, voice_stack, |
668 | sizeof(voice_stack), voice_thread_name); | 670 | sizeof(voice_stack), voice_thread_name |
671 | IF_PRIO(, PRIORITY_PLAYBACK)); | ||
669 | 672 | ||
670 | while (!voice_codec_loaded) | 673 | while (!voice_codec_loaded) |
671 | yield(); | 674 | yield(); |
@@ -1740,7 +1743,7 @@ static void codec_thread(void) | |||
1740 | #endif | 1743 | #endif |
1741 | 1744 | ||
1742 | #ifndef SIMULATOR | 1745 | #ifndef SIMULATOR |
1743 | case SYS_USB_CONNECTED: | 1746 | case SYS_USB_CONNECTED: |
1744 | LOGFQUEUE("codec < SYS_USB_CONNECTED"); | 1747 | LOGFQUEUE("codec < SYS_USB_CONNECTED"); |
1745 | queue_clear(&codec_queue); | 1748 | queue_clear(&codec_queue); |
1746 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | 1749 | usb_acknowledge(SYS_USB_CONNECTED_ACK); |
@@ -1982,13 +1985,15 @@ static bool audio_yield_codecs(void) | |||
1982 | { | 1985 | { |
1983 | yield(); | 1986 | yield(); |
1984 | 1987 | ||
1985 | if (!queue_empty(&audio_queue)) return true; | 1988 | if (!queue_empty(&audio_queue)) |
1989 | return true; | ||
1986 | 1990 | ||
1987 | while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata()) | 1991 | while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata()) |
1988 | && !ci.stop_codec && playing && !audio_filebuf_is_lowdata()) | 1992 | && !ci.stop_codec && playing && !audio_filebuf_is_lowdata()) |
1989 | { | 1993 | { |
1990 | sleep(1); | 1994 | sleep(1); |
1991 | if (!queue_empty(&audio_queue)) return true; | 1995 | if (!queue_empty(&audio_queue)) |
1996 | return true; | ||
1992 | } | 1997 | } |
1993 | 1998 | ||
1994 | return false; | 1999 | return false; |
@@ -3178,8 +3183,9 @@ static void audio_playback_init(void) | |||
3178 | id3_voice.frequency = 11200; | 3183 | id3_voice.frequency = 11200; |
3179 | id3_voice.length = 1000000L; | 3184 | id3_voice.length = 1000000L; |
3180 | 3185 | ||
3181 | create_thread(codec_thread, codec_stack, sizeof(codec_stack), | 3186 | codec_thread_p = create_thread(codec_thread, codec_stack, |
3182 | codec_thread_name); | 3187 | sizeof(codec_stack), |
3188 | codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)); | ||
3183 | 3189 | ||
3184 | while (1) | 3190 | while (1) |
3185 | { | 3191 | { |
@@ -3213,7 +3219,8 @@ static void audio_thread(void) | |||
3213 | /* At first initialize audio system in background. */ | 3219 | /* At first initialize audio system in background. */ |
3214 | audio_playback_init(); | 3220 | audio_playback_init(); |
3215 | 3221 | ||
3216 | while (1) { | 3222 | while (1) |
3223 | { | ||
3217 | if (filling) | 3224 | if (filling) |
3218 | { | 3225 | { |
3219 | queue_wait_w_tmo(&audio_queue, &ev, 0); | 3226 | queue_wait_w_tmo(&audio_queue, &ev, 0); |
@@ -3221,7 +3228,7 @@ static void audio_thread(void) | |||
3221 | ev.id = Q_AUDIO_FILL_BUFFER; | 3228 | ev.id = Q_AUDIO_FILL_BUFFER; |
3222 | } | 3229 | } |
3223 | else | 3230 | else |
3224 | queue_wait_w_tmo(&audio_queue, &ev, HZ); | 3231 | queue_wait_w_tmo(&audio_queue, &ev, HZ/2); |
3225 | 3232 | ||
3226 | switch (ev.id) { | 3233 | switch (ev.id) { |
3227 | case Q_AUDIO_FILL_BUFFER: | 3234 | case Q_AUDIO_FILL_BUFFER: |
diff --git a/apps/playlist.c b/apps/playlist.c index a75e32aed5..4ab98ab3c6 100644 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -1777,8 +1777,8 @@ void playlist_init(void) | |||
1777 | memset(playlist->filenames, 0, | 1777 | memset(playlist->filenames, 0, |
1778 | playlist->max_playlist_size * sizeof(int)); | 1778 | playlist->max_playlist_size * sizeof(int)); |
1779 | create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack), | 1779 | create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack), |
1780 | playlist_thread_name); | 1780 | playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND)); |
1781 | queue_init(&playlist_queue); | 1781 | queue_init(&playlist_queue, true); |
1782 | #endif | 1782 | #endif |
1783 | } | 1783 | } |
1784 | 1784 | ||
diff --git a/apps/plugin.c b/apps/plugin.c index 6e2a8bca37..9ffb980300 100644 --- a/apps/plugin.c +++ b/apps/plugin.c | |||
@@ -108,6 +108,7 @@ static const struct plugin_api rockbox_api = { | |||
108 | PREFIX(lcd_icon), | 108 | PREFIX(lcd_icon), |
109 | lcd_double_height, | 109 | lcd_double_height, |
110 | #else | 110 | #else |
111 | lcd_setmargins, | ||
111 | lcd_set_drawmode, | 112 | lcd_set_drawmode, |
112 | lcd_get_drawmode, | 113 | lcd_get_drawmode, |
113 | lcd_setfont, | 114 | lcd_setfont, |
@@ -132,6 +133,9 @@ static const struct plugin_api rockbox_api = { | |||
132 | lcd_bitmap_transparent_part, | 133 | lcd_bitmap_transparent_part, |
133 | lcd_bitmap_transparent, | 134 | lcd_bitmap_transparent, |
134 | #endif | 135 | #endif |
136 | bidi_l2v, | ||
137 | font_get_bits, | ||
138 | font_load, | ||
135 | lcd_putsxy, | 139 | lcd_putsxy, |
136 | lcd_puts_style, | 140 | lcd_puts_style, |
137 | lcd_puts_scroll_style, | 141 | lcd_puts_scroll_style, |
@@ -178,6 +182,45 @@ static const struct plugin_api rockbox_api = { | |||
178 | remote_backlight_on, | 182 | remote_backlight_on, |
179 | remote_backlight_off, | 183 | remote_backlight_off, |
180 | #endif | 184 | #endif |
185 | #if NB_SCREENS == 2 | ||
186 | {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]}, | ||
187 | #else | ||
188 | {&screens[SCREEN_MAIN]}, | ||
189 | #endif | ||
190 | #if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | ||
191 | lcd_remote_set_foreground, | ||
192 | lcd_remote_get_foreground, | ||
193 | lcd_remote_set_background, | ||
194 | lcd_remote_get_background, | ||
195 | lcd_remote_bitmap_part, | ||
196 | lcd_remote_bitmap, | ||
197 | #endif | ||
198 | |||
199 | #if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) | ||
200 | lcd_yuv_blit, | ||
201 | #endif | ||
202 | /* list */ | ||
203 | gui_synclist_init, | ||
204 | gui_synclist_set_nb_items, | ||
205 | gui_synclist_set_icon_callback, | ||
206 | gui_synclist_get_nb_items, | ||
207 | gui_synclist_get_sel_pos, | ||
208 | gui_synclist_draw, | ||
209 | gui_synclist_select_item, | ||
210 | gui_synclist_select_next, | ||
211 | gui_synclist_select_previous, | ||
212 | gui_synclist_select_next_page, | ||
213 | gui_synclist_select_previous_page, | ||
214 | gui_synclist_add_item, | ||
215 | gui_synclist_del_item, | ||
216 | gui_synclist_limit_scroll, | ||
217 | gui_synclist_flash, | ||
218 | #ifdef HAVE_LCD_BITMAP | ||
219 | gui_synclist_scroll_right, | ||
220 | gui_synclist_scroll_left, | ||
221 | #endif | ||
222 | gui_synclist_do_button, | ||
223 | |||
181 | /* button */ | 224 | /* button */ |
182 | button_get, | 225 | button_get, |
183 | button_get_w_tmo, | 226 | button_get_w_tmo, |
@@ -205,12 +248,14 @@ static const struct plugin_api rockbox_api = { | |||
205 | ata_sleep, | 248 | ata_sleep, |
206 | ata_disk_is_active, | 249 | ata_disk_is_active, |
207 | #endif | 250 | #endif |
251 | reload_directory, | ||
208 | 252 | ||
209 | /* dir */ | 253 | /* dir */ |
210 | PREFIX(opendir), | 254 | PREFIX(opendir), |
211 | PREFIX(closedir), | 255 | PREFIX(closedir), |
212 | PREFIX(readdir), | 256 | PREFIX(readdir), |
213 | PREFIX(mkdir), | 257 | PREFIX(mkdir), |
258 | PREFIX(rmdir), | ||
214 | 259 | ||
215 | /* kernel/ system */ | 260 | /* kernel/ system */ |
216 | PREFIX(sleep), | 261 | PREFIX(sleep), |
@@ -253,6 +298,7 @@ static const struct plugin_api rockbox_api = { | |||
253 | 298 | ||
254 | /* strings and memory */ | 299 | /* strings and memory */ |
255 | snprintf, | 300 | snprintf, |
301 | vsnprintf, | ||
256 | strcpy, | 302 | strcpy, |
257 | strncpy, | 303 | strncpy, |
258 | strlen, | 304 | strlen, |
@@ -268,6 +314,7 @@ static const struct plugin_api rockbox_api = { | |||
268 | atoi, | 314 | atoi, |
269 | strchr, | 315 | strchr, |
270 | strcat, | 316 | strcat, |
317 | memchr, | ||
271 | memcmp, | 318 | memcmp, |
272 | strcasestr, | 319 | strcasestr, |
273 | /* unicode stuff */ | 320 | /* unicode stuff */ |
@@ -277,9 +324,12 @@ static const struct plugin_api rockbox_api = { | |||
277 | utf16BEdecode, | 324 | utf16BEdecode, |
278 | utf8encode, | 325 | utf8encode, |
279 | utf8length, | 326 | utf8length, |
327 | utf8seek, | ||
280 | 328 | ||
281 | /* sound */ | 329 | /* sound */ |
282 | sound_set, | 330 | sound_set, |
331 | set_sound, | ||
332 | |||
283 | sound_min, | 333 | sound_min, |
284 | sound_max, | 334 | sound_max, |
285 | #ifndef SIMULATOR | 335 | #ifndef SIMULATOR |
@@ -334,6 +384,9 @@ static const struct plugin_api rockbox_api = { | |||
334 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | 384 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) |
335 | mas_codec_writereg, | 385 | mas_codec_writereg, |
336 | mas_codec_readreg, | 386 | mas_codec_readreg, |
387 | i2c_begin, | ||
388 | i2c_end, | ||
389 | i2c_write, | ||
337 | #endif | 390 | #endif |
338 | #endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */ | 391 | #endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */ |
339 | 392 | ||
@@ -352,7 +405,15 @@ static const struct plugin_api rockbox_api = { | |||
352 | menu_insert, | 405 | menu_insert, |
353 | menu_set_cursor, | 406 | menu_set_cursor, |
354 | set_option, | 407 | set_option, |
408 | set_int, | ||
409 | set_bool, | ||
355 | 410 | ||
411 | /* action handling */ | ||
412 | get_custom_action, | ||
413 | get_action, | ||
414 | action_signalscreenchange, | ||
415 | action_userabort, | ||
416 | |||
356 | /* power */ | 417 | /* power */ |
357 | battery_level, | 418 | battery_level, |
358 | battery_level_safe, | 419 | battery_level_safe, |
@@ -405,74 +466,6 @@ static const struct plugin_api rockbox_api = { | |||
405 | 466 | ||
406 | /* new stuff at the end, sort into place next time | 467 | /* new stuff at the end, sort into place next time |
407 | the API gets incompatible */ | 468 | the API gets incompatible */ |
408 | set_sound, | ||
409 | #if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR) | ||
410 | i2c_begin, | ||
411 | i2c_end, | ||
412 | i2c_write, | ||
413 | #endif | ||
414 | |||
415 | vsnprintf, | ||
416 | memchr, | ||
417 | /* list */ | ||
418 | gui_synclist_init, | ||
419 | gui_synclist_set_nb_items, | ||
420 | gui_synclist_set_icon_callback, | ||
421 | gui_synclist_get_nb_items, | ||
422 | gui_synclist_get_sel_pos, | ||
423 | gui_synclist_draw, | ||
424 | gui_synclist_select_item, | ||
425 | gui_synclist_select_next, | ||
426 | gui_synclist_select_previous, | ||
427 | gui_synclist_select_next_page, | ||
428 | gui_synclist_select_previous_page, | ||
429 | gui_synclist_add_item, | ||
430 | gui_synclist_del_item, | ||
431 | gui_synclist_limit_scroll, | ||
432 | gui_synclist_flash, | ||
433 | #ifdef HAVE_LCD_BITMAP | ||
434 | gui_synclist_scroll_right, | ||
435 | gui_synclist_scroll_left, | ||
436 | #endif | ||
437 | gui_synclist_do_button, | ||
438 | |||
439 | #ifdef HAVE_LCD_BITMAP | ||
440 | lcd_setmargins, | ||
441 | #endif | ||
442 | utf8seek, | ||
443 | |||
444 | set_int, | ||
445 | reload_directory, | ||
446 | set_bool, | ||
447 | #if NB_SCREENS == 2 | ||
448 | {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]}, | ||
449 | #else | ||
450 | {&screens[SCREEN_MAIN]}, | ||
451 | #endif | ||
452 | #ifdef HAVE_LCD_BITMAP | ||
453 | bidi_l2v, | ||
454 | font_get_bits, | ||
455 | font_load, | ||
456 | #endif | ||
457 | #if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | ||
458 | lcd_remote_set_foreground, | ||
459 | lcd_remote_get_foreground, | ||
460 | lcd_remote_set_background, | ||
461 | lcd_remote_get_background, | ||
462 | lcd_remote_bitmap_part, | ||
463 | lcd_remote_bitmap, | ||
464 | #endif | ||
465 | |||
466 | #if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) | ||
467 | lcd_yuv_blit, | ||
468 | #endif | ||
469 | |||
470 | PREFIX(rmdir), | ||
471 | /* action handling */ | ||
472 | get_custom_action, | ||
473 | get_action, | ||
474 | action_signalscreenchange, | ||
475 | action_userabort, | ||
476 | }; | 469 | }; |
477 | 470 | ||
478 | int plugin_load(const char* plugin, void* parameter) | 471 | int plugin_load(const char* plugin, void* parameter) |
diff --git a/apps/plugin.h b/apps/plugin.h index 9b3cec5cde..b89dfd0d81 100644 --- a/apps/plugin.h +++ b/apps/plugin.h | |||
@@ -105,12 +105,12 @@ | |||
105 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ | 105 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ |
106 | 106 | ||
107 | /* increase this every time the api struct changes */ | 107 | /* increase this every time the api struct changes */ |
108 | #define PLUGIN_API_VERSION 29 | 108 | #define PLUGIN_API_VERSION 30 |
109 | 109 | ||
110 | /* update this to latest version if a change to the api struct breaks | 110 | /* update this to latest version if a change to the api struct breaks |
111 | backwards compatibility (and please take the opportunity to sort in any | 111 | backwards compatibility (and please take the opportunity to sort in any |
112 | new function which are "waiting" at the end of the function table) */ | 112 | new function which are "waiting" at the end of the function table) */ |
113 | #define PLUGIN_MIN_API_VERSION 14 | 113 | #define PLUGIN_MIN_API_VERSION 30 |
114 | 114 | ||
115 | /* plugin return codes */ | 115 | /* plugin return codes */ |
116 | enum plugin_status { | 116 | enum plugin_status { |
@@ -143,6 +143,7 @@ struct plugin_api { | |||
143 | void (*PREFIX(lcd_icon))(int icon, bool enable); | 143 | void (*PREFIX(lcd_icon))(int icon, bool enable); |
144 | void (*lcd_double_height)(bool on); | 144 | void (*lcd_double_height)(bool on); |
145 | #else | 145 | #else |
146 | void (*lcd_setmargins)(int x, int y); | ||
146 | void (*lcd_set_drawmode)(int mode); | 147 | void (*lcd_set_drawmode)(int mode); |
147 | int (*lcd_get_drawmode)(void); | 148 | int (*lcd_get_drawmode)(void); |
148 | void (*lcd_setfont)(int font); | 149 | void (*lcd_setfont)(int font); |
@@ -174,6 +175,9 @@ struct plugin_api { | |||
174 | void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y, | 175 | void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y, |
175 | int width, int height); | 176 | int width, int height); |
176 | #endif | 177 | #endif |
178 | unsigned short *(*bidi_l2v)( const unsigned char *str, int orientation ); | ||
179 | const unsigned char *(*font_get_bits)( struct font *pf, unsigned short char_code ); | ||
180 | struct font* (*font_load)(const char *path); | ||
177 | void (*lcd_putsxy)(int x, int y, const unsigned char *string); | 181 | void (*lcd_putsxy)(int x, int y, const unsigned char *string); |
178 | void (*lcd_puts_style)(int x, int y, const unsigned char *str, int style); | 182 | void (*lcd_puts_style)(int x, int y, const unsigned char *str, int style); |
179 | void (*lcd_puts_scroll_style)(int x, int y, const unsigned char* string, | 183 | void (*lcd_puts_scroll_style)(int x, int y, const unsigned char* string, |
@@ -229,7 +233,50 @@ struct plugin_api { | |||
229 | void (*remote_backlight_on)(void); | 233 | void (*remote_backlight_on)(void); |
230 | void (*remote_backlight_off)(void); | 234 | void (*remote_backlight_off)(void); |
231 | #endif | 235 | #endif |
236 | struct screen* screens[NB_SCREENS]; | ||
237 | #if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | ||
238 | void (*lcd_remote_set_foreground)(unsigned foreground); | ||
239 | unsigned (*lcd_remote_get_foreground)(void); | ||
240 | void (*lcd_remote_set_background)(unsigned foreground); | ||
241 | unsigned (*lcd_remote_get_background)(void); | ||
242 | void (*lcd_remote_bitmap_part)(const fb_remote_data *src, int src_x, int src_y, | ||
243 | int stride, int x, int y, int width, int height); | ||
244 | void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width, | ||
245 | int height); | ||
246 | #endif | ||
247 | #if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) | ||
248 | void (*lcd_yuv_blit)(unsigned char * const src[3], | ||
249 | int src_x, int src_y, int stride, | ||
250 | int x, int y, int width, int height); | ||
251 | #endif | ||
232 | 252 | ||
253 | /* list */ | ||
254 | void (*gui_synclist_init)(struct gui_synclist * lists, | ||
255 | list_get_name callback_get_item_name,void * data, | ||
256 | bool scroll_all,int selected_size); | ||
257 | void (*gui_synclist_set_nb_items)(struct gui_synclist * lists, int nb_items); | ||
258 | void (*gui_synclist_set_icon_callback)(struct gui_synclist * lists, list_get_icon icon_callback); | ||
259 | int (*gui_synclist_get_nb_items)(struct gui_synclist * lists); | ||
260 | int (*gui_synclist_get_sel_pos)(struct gui_synclist * lists); | ||
261 | void (*gui_synclist_draw)(struct gui_synclist * lists); | ||
262 | void (*gui_synclist_select_item)(struct gui_synclist * lists, | ||
263 | int item_number); | ||
264 | void (*gui_synclist_select_next)(struct gui_synclist * lists); | ||
265 | void (*gui_synclist_select_previous)(struct gui_synclist * lists); | ||
266 | void (*gui_synclist_select_next_page)(struct gui_synclist * lists, | ||
267 | enum screen_type screen); | ||
268 | void (*gui_synclist_select_previous_page)(struct gui_synclist * lists, | ||
269 | enum screen_type screen); | ||
270 | void (*gui_synclist_add_item)(struct gui_synclist * lists); | ||
271 | void (*gui_synclist_del_item)(struct gui_synclist * lists); | ||
272 | void (*gui_synclist_limit_scroll)(struct gui_synclist * lists, bool scroll); | ||
273 | void (*gui_synclist_flash)(struct gui_synclist * lists); | ||
274 | #ifdef HAVE_LCD_BITMAP | ||
275 | void (*gui_synclist_scroll_right)(struct gui_synclist * lists); | ||
276 | void (*gui_synclist_scroll_left)(struct gui_synclist * lists); | ||
277 | #endif | ||
278 | unsigned (*gui_synclist_do_button)(struct gui_synclist * lists, unsigned button); | ||
279 | |||
233 | /* button */ | 280 | /* button */ |
234 | long (*button_get)(bool block); | 281 | long (*button_get)(bool block); |
235 | long (*button_get_w_tmo)(int ticks); | 282 | long (*button_get_w_tmo)(int ticks); |
@@ -257,12 +304,14 @@ struct plugin_api { | |||
257 | void (*ata_sleep)(void); | 304 | void (*ata_sleep)(void); |
258 | bool (*ata_disk_is_active)(void); | 305 | bool (*ata_disk_is_active)(void); |
259 | #endif | 306 | #endif |
307 | void (*reload_directory)(void); | ||
260 | 308 | ||
261 | /* dir */ | 309 | /* dir */ |
262 | DIR* (*PREFIX(opendir))(const char* name); | 310 | DIR* (*PREFIX(opendir))(const char* name); |
263 | int (*PREFIX(closedir))(DIR* dir); | 311 | int (*PREFIX(closedir))(DIR* dir); |
264 | struct dirent* (*PREFIX(readdir))(DIR* dir); | 312 | struct dirent* (*PREFIX(readdir))(DIR* dir); |
265 | int (*PREFIX(mkdir))(const char *name, int mode); | 313 | int (*PREFIX(mkdir))(const char *name, int mode); |
314 | int (*PREFIX(rmdir))(const char *name); | ||
266 | 315 | ||
267 | /* kernel/ system */ | 316 | /* kernel/ system */ |
268 | void (*PREFIX(sleep))(int ticks); | 317 | void (*PREFIX(sleep))(int ticks); |
@@ -270,8 +319,10 @@ struct plugin_api { | |||
270 | long* current_tick; | 319 | long* current_tick; |
271 | long (*default_event_handler)(long event); | 320 | long (*default_event_handler)(long event); |
272 | long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); | 321 | long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter); |
273 | int (*create_thread)(void (*function)(void), void* stack, int stack_size, const char *name); | 322 | struct thread_entry* (*create_thread)(void (*function)(void), void* stack, |
274 | void (*remove_thread)(int threadnum); | 323 | int stack_size, const char *name |
324 | IF_PRIO(, int priority)); | ||
325 | void (*remove_thread)(struct thread_entry *thread); | ||
275 | void (*reset_poweroff_timer)(void); | 326 | void (*reset_poweroff_timer)(void); |
276 | #ifndef SIMULATOR | 327 | #ifndef SIMULATOR |
277 | int (*system_memory_guard)(int newmode); | 328 | int (*system_memory_guard)(int newmode); |
@@ -285,7 +336,7 @@ struct plugin_api { | |||
285 | void (*timer_unregister)(void); | 336 | void (*timer_unregister)(void); |
286 | bool (*timer_set_period)(long count); | 337 | bool (*timer_set_period)(long count); |
287 | #endif | 338 | #endif |
288 | void (*queue_init)(struct event_queue *q); | 339 | void (*queue_init)(struct event_queue *q, bool register_queue); |
289 | void (*queue_delete)(struct event_queue *q); | 340 | void (*queue_delete)(struct event_queue *q); |
290 | void (*queue_post)(struct event_queue *q, long id, void *data); | 341 | void (*queue_post)(struct event_queue *q, long id, void *data); |
291 | void (*queue_wait_w_tmo)(struct event_queue *q, struct event *ev, | 342 | void (*queue_wait_w_tmo)(struct event_queue *q, struct event *ev, |
@@ -308,6 +359,7 @@ struct plugin_api { | |||
308 | 359 | ||
309 | /* strings and memory */ | 360 | /* strings and memory */ |
310 | int (*snprintf)(char *buf, size_t size, const char *fmt, ...); | 361 | int (*snprintf)(char *buf, size_t size, const char *fmt, ...); |
362 | int (*vsnprintf)(char *buf, int size, const char *fmt, va_list ap); | ||
311 | char* (*strcpy)(char *dst, const char *src); | 363 | char* (*strcpy)(char *dst, const char *src); |
312 | char* (*strncpy)(char *dst, const char *src, size_t length); | 364 | char* (*strncpy)(char *dst, const char *src, size_t length); |
313 | size_t (*strlen)(const char *str); | 365 | size_t (*strlen)(const char *str); |
@@ -323,6 +375,7 @@ struct plugin_api { | |||
323 | int (*atoi)(const char *str); | 375 | int (*atoi)(const char *str); |
324 | char *(*strchr)(const char *s, int c); | 376 | char *(*strchr)(const char *s, int c); |
325 | char *(*strcat)(char *s1, const char *s2); | 377 | char *(*strcat)(char *s1, const char *s2); |
378 | void *(*memchr)(const void *s1, int c, size_t n); | ||
326 | int (*memcmp)(const void *s1, const void *s2, size_t n); | 379 | int (*memcmp)(const void *s1, const void *s2, size_t n); |
327 | char *(*strcasestr) (const char* phaystack, const char* pneedle); | 380 | char *(*strcasestr) (const char* phaystack, const char* pneedle); |
328 | /* unicode stuff */ | 381 | /* unicode stuff */ |
@@ -332,9 +385,12 @@ struct plugin_api { | |||
332 | unsigned char* (*utf16BEdecode)(const unsigned char *utf16, unsigned char *utf8, int count); | 385 | unsigned char* (*utf16BEdecode)(const unsigned char *utf16, unsigned char *utf8, int count); |
333 | unsigned char* (*utf8encode)(unsigned long ucs, unsigned char *utf8); | 386 | unsigned char* (*utf8encode)(unsigned long ucs, unsigned char *utf8); |
334 | unsigned long (*utf8length)(const unsigned char *utf8); | 387 | unsigned long (*utf8length)(const unsigned char *utf8); |
388 | int (*utf8seek)(const unsigned char* utf8, int offset); | ||
335 | 389 | ||
336 | /* sound */ | 390 | /* sound */ |
337 | void (*sound_set)(int setting, int value); | 391 | void (*sound_set)(int setting, int value); |
392 | bool (*set_sound)(const unsigned char * string, | ||
393 | int* variable, int setting); | ||
338 | int (*sound_min)(int setting); | 394 | int (*sound_min)(int setting); |
339 | int (*sound_max)(int setting); | 395 | int (*sound_max)(int setting); |
340 | #ifndef SIMULATOR | 396 | #ifndef SIMULATOR |
@@ -390,6 +446,9 @@ struct plugin_api { | |||
390 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | 446 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) |
391 | int (*mas_codec_writereg)(int reg, unsigned int val); | 447 | int (*mas_codec_writereg)(int reg, unsigned int val); |
392 | int (*mas_codec_readreg)(int reg); | 448 | int (*mas_codec_readreg)(int reg); |
449 | void (*i2c_begin)(void); | ||
450 | void (*i2c_end)(void); | ||
451 | int (*i2c_write)(int address, unsigned char* buf, int count ); | ||
393 | #endif | 452 | #endif |
394 | #endif | 453 | #endif |
395 | 454 | ||
@@ -413,7 +472,17 @@ struct plugin_api { | |||
413 | bool (*set_option)(const char* string, void* variable, | 472 | bool (*set_option)(const char* string, void* variable, |
414 | enum optiontype type, const struct opt_items* options, | 473 | enum optiontype type, const struct opt_items* options, |
415 | int numoptions, void (*function)(int)); | 474 | int numoptions, void (*function)(int)); |
475 | bool (*set_int)(const unsigned char* string, const char* unit, int voice_unit, | ||
476 | int* variable, void (*function)(int), int step, int min, | ||
477 | int max, void (*formatter)(char*, int, int, const char*) ); | ||
478 | bool (*set_bool)(const char* string, bool* variable ); | ||
416 | 479 | ||
480 | /* action handling */ | ||
481 | int (*get_custom_action)(int context,int timeout, | ||
482 | const struct button_mapping* (*get_context_map)(int)); | ||
483 | int (*get_action)(int context, int timeout); | ||
484 | void (*action_signalscreenchange)(void); | ||
485 | bool (*action_userabort)(int timeout); | ||
417 | 486 | ||
418 | /* power */ | 487 | /* power */ |
419 | int (*battery_level)(void); | 488 | int (*battery_level)(void); |
@@ -476,83 +545,6 @@ struct plugin_api { | |||
476 | 545 | ||
477 | /* new stuff at the end, sort into place next time | 546 | /* new stuff at the end, sort into place next time |
478 | the API gets incompatible */ | 547 | the API gets incompatible */ |
479 | bool (*set_sound)(const unsigned char * string, | ||
480 | int* variable, int setting); | ||
481 | #if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR) | ||
482 | void (*i2c_begin)(void); | ||
483 | void (*i2c_end)(void); | ||
484 | int (*i2c_write)(int address, unsigned char* buf, int count ); | ||
485 | #endif | ||
486 | |||
487 | int (*vsnprintf)(char *buf, int size, const char *fmt, va_list ap); | ||
488 | void *(*memchr)(const void *s1, int c, size_t n); | ||
489 | |||
490 | /* list */ | ||
491 | void (*gui_synclist_init)(struct gui_synclist * lists, | ||
492 | list_get_name callback_get_item_name,void * data, | ||
493 | bool scroll_all,int selected_size); | ||
494 | void (*gui_synclist_set_nb_items)(struct gui_synclist * lists, int nb_items); | ||
495 | void (*gui_synclist_set_icon_callback)(struct gui_synclist * lists, list_get_icon icon_callback); | ||
496 | int (*gui_synclist_get_nb_items)(struct gui_synclist * lists); | ||
497 | int (*gui_synclist_get_sel_pos)(struct gui_synclist * lists); | ||
498 | void (*gui_synclist_draw)(struct gui_synclist * lists); | ||
499 | void (*gui_synclist_select_item)(struct gui_synclist * lists, | ||
500 | int item_number); | ||
501 | void (*gui_synclist_select_next)(struct gui_synclist * lists); | ||
502 | void (*gui_synclist_select_previous)(struct gui_synclist * lists); | ||
503 | void (*gui_synclist_select_next_page)(struct gui_synclist * lists, | ||
504 | enum screen_type screen); | ||
505 | void (*gui_synclist_select_previous_page)(struct gui_synclist * lists, | ||
506 | enum screen_type screen); | ||
507 | void (*gui_synclist_add_item)(struct gui_synclist * lists); | ||
508 | void (*gui_synclist_del_item)(struct gui_synclist * lists); | ||
509 | void (*gui_synclist_limit_scroll)(struct gui_synclist * lists, bool scroll); | ||
510 | void (*gui_synclist_flash)(struct gui_synclist * lists); | ||
511 | #ifdef HAVE_LCD_BITMAP | ||
512 | void (*gui_synclist_scroll_right)(struct gui_synclist * lists); | ||
513 | void (*gui_synclist_scroll_left)(struct gui_synclist * lists); | ||
514 | #endif | ||
515 | unsigned (*gui_synclist_do_button)(struct gui_synclist * lists, unsigned button); | ||
516 | |||
517 | #ifdef HAVE_LCD_BITMAP | ||
518 | void (*lcd_setmargins)(int x, int y); | ||
519 | #endif | ||
520 | int (*utf8seek)(const unsigned char* utf8, int offset); | ||
521 | |||
522 | bool (*set_int)(const unsigned char* string, const char* unit, int voice_unit, | ||
523 | int* variable, void (*function)(int), int step, int min, | ||
524 | int max, void (*formatter)(char*, int, int, const char*) ); | ||
525 | void (*reload_directory)(void); | ||
526 | bool (*set_bool)(const char* string, bool* variable ); | ||
527 | struct screen* screens[NB_SCREENS]; | ||
528 | #ifdef HAVE_LCD_BITMAP | ||
529 | unsigned short *(*bidi_l2v)( const unsigned char *str, int orientation ); | ||
530 | const unsigned char *(*font_get_bits)( struct font *pf, unsigned short char_code ); | ||
531 | struct font* (*font_load)(const char *path); | ||
532 | #endif | ||
533 | #if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | ||
534 | void (*lcd_remote_set_foreground)(unsigned foreground); | ||
535 | unsigned (*lcd_remote_get_foreground)(void); | ||
536 | void (*lcd_remote_set_background)(unsigned foreground); | ||
537 | unsigned (*lcd_remote_get_background)(void); | ||
538 | void (*lcd_remote_bitmap_part)(const fb_remote_data *src, int src_x, int src_y, | ||
539 | int stride, int x, int y, int width, int height); | ||
540 | void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width, | ||
541 | int height); | ||
542 | #endif | ||
543 | #if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) | ||
544 | void (*lcd_yuv_blit)(unsigned char * const src[3], | ||
545 | int src_x, int src_y, int stride, | ||
546 | int x, int y, int width, int height); | ||
547 | #endif | ||
548 | |||
549 | int (*PREFIX(rmdir))(const char *name); | ||
550 | /* action handling */ | ||
551 | int (*get_custom_action)(int context,int timeout, | ||
552 | const struct button_mapping* (*get_context_map)(int)); | ||
553 | int (*get_action)(int context, int timeout); | ||
554 | void (*action_signalscreenchange)(void); | ||
555 | bool (*action_userabort)(int timeout); | ||
556 | }; | 548 | }; |
557 | 549 | ||
558 | /* plugin header */ | 550 | /* plugin header */ |
diff --git a/apps/plugins/alpine_cdc.c b/apps/plugins/alpine_cdc.c index a482664d6a..134bb3dee6 100644 --- a/apps/plugins/alpine_cdc.c +++ b/apps/plugins/alpine_cdc.c | |||
@@ -202,7 +202,7 @@ struct | |||
202 | /* communication to the worker thread */ | 202 | /* communication to the worker thread */ |
203 | struct | 203 | struct |
204 | { | 204 | { |
205 | int id; /* ID of the thread */ | 205 | struct thread_entry *id; /* Pointer of the thread */ |
206 | bool foreground; /* set as long as we're owning the UI */ | 206 | bool foreground; /* set as long as we're owning the UI */ |
207 | bool exiting; /* signal to the thread that we want to exit */ | 207 | bool exiting; /* signal to the thread that we want to exit */ |
208 | bool ended; /* response from the thread, that is has exited */ | 208 | bool ended; /* response from the thread, that is has exited */ |
@@ -1169,7 +1169,8 @@ int main(void* parameter) | |||
1169 | 1169 | ||
1170 | rb->memset(&gTread, 0, sizeof(gTread)); | 1170 | rb->memset(&gTread, 0, sizeof(gTread)); |
1171 | gTread.foreground = true; | 1171 | gTread.foreground = true; |
1172 | gTread.id = rb->create_thread(thread, stack, stacksize, "CDC"); | 1172 | gTread.id = rb->create_thread(thread, stack, stacksize, "CDC" |
1173 | IF_PRIO(, PRIORITY_BACKGROUND)); | ||
1173 | 1174 | ||
1174 | #ifdef DEBUG | 1175 | #ifdef DEBUG |
1175 | do | 1176 | do |
diff --git a/apps/plugins/battery_bench.c b/apps/plugins/battery_bench.c index 9400bd2018..3c56f84309 100644 --- a/apps/plugins/battery_bench.c +++ b/apps/plugins/battery_bench.c | |||
@@ -102,7 +102,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
102 | 102 | ||
103 | struct | 103 | struct |
104 | { | 104 | { |
105 | int id; | 105 | struct thread_entry *id; |
106 | bool ended; | 106 | bool ended; |
107 | } s_thread; | 107 | } s_thread; |
108 | 108 | ||
@@ -454,10 +454,11 @@ int main(void) | |||
454 | rb->close(fd); | 454 | rb->close(fd); |
455 | } | 455 | } |
456 | 456 | ||
457 | rb->queue_init(&thread_q); /* put the thread's queue in the bcast list */ | 457 | rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */ |
458 | rb->memset(&s_thread, 0, sizeof(s_thread)); /* zero the struct */ | 458 | rb->memset(&s_thread, 0, sizeof(s_thread)); /* zero the struct */ |
459 | if((s_thread.id = rb->create_thread(thread, thread_stack, | 459 | if((s_thread.id = rb->create_thread(thread, thread_stack, |
460 | sizeof(thread_stack), "Battery Benchmark"))<0) | 460 | sizeof(thread_stack), "Battery Benchmark" |
461 | IF_PRIO(, PRIORITY_BACKGROUND))) == NULL) | ||
461 | { | 462 | { |
462 | rb->splash(HZ,true,"Cannot create thread!"); | 463 | rb->splash(HZ,true,"Cannot create thread!"); |
463 | return PLUGIN_ERROR; | 464 | return PLUGIN_ERROR; |
diff --git a/apps/tagcache.c b/apps/tagcache.c index 2ed80a860b..f478598dad 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c | |||
@@ -54,6 +54,7 @@ | |||
54 | */ | 54 | */ |
55 | 55 | ||
56 | #include <stdio.h> | 56 | #include <stdio.h> |
57 | #include "config.h" | ||
57 | #include "thread.h" | 58 | #include "thread.h" |
58 | #include "kernel.h" | 59 | #include "kernel.h" |
59 | #include "system.h" | 60 | #include "system.h" |
@@ -1062,7 +1063,6 @@ static bool get_next(struct tagcache_search *tcs) | |||
1062 | 1063 | ||
1063 | if (tagcache_is_numeric_tag(tcs->type)) | 1064 | if (tagcache_is_numeric_tag(tcs->type)) |
1064 | { | 1065 | { |
1065 | logf("r:%d", tcs->position); | ||
1066 | snprintf(buf, sizeof(buf), "%d", tcs->position); | 1066 | snprintf(buf, sizeof(buf), "%d", tcs->position); |
1067 | tcs->result_seek = tcs->position; | 1067 | tcs->result_seek = tcs->position; |
1068 | tcs->result = buf; | 1068 | tcs->result = buf; |
@@ -3455,7 +3455,6 @@ static void tagcache_thread(void) | |||
3455 | sleep(HZ); | 3455 | sleep(HZ); |
3456 | stat.ready = check_all_headers(); | 3456 | stat.ready = check_all_headers(); |
3457 | 3457 | ||
3458 | |||
3459 | while (1) | 3458 | while (1) |
3460 | { | 3459 | { |
3461 | queue_wait_w_tmo(&tagcache_queue, &ev, HZ); | 3460 | queue_wait_w_tmo(&tagcache_queue, &ev, HZ); |
@@ -3503,6 +3502,7 @@ static void tagcache_thread(void) | |||
3503 | 3502 | ||
3504 | 3503 | ||
3505 | logf("tagcache check done"); | 3504 | logf("tagcache check done"); |
3505 | |||
3506 | check_done = true; | 3506 | check_done = true; |
3507 | break ; | 3507 | break ; |
3508 | 3508 | ||
@@ -3612,9 +3612,10 @@ void tagcache_init(void) | |||
3612 | current_serial = 0; | 3612 | current_serial = 0; |
3613 | write_lock = read_lock = 0; | 3613 | write_lock = read_lock = 0; |
3614 | 3614 | ||
3615 | queue_init(&tagcache_queue); | 3615 | queue_init(&tagcache_queue, true); |
3616 | create_thread(tagcache_thread, tagcache_stack, | 3616 | create_thread(tagcache_thread, tagcache_stack, |
3617 | sizeof(tagcache_stack), tagcache_thread_name); | 3617 | sizeof(tagcache_stack), tagcache_thread_name |
3618 | IF_PRIO(, PRIORITY_BACKGROUND)); | ||
3618 | } | 3619 | } |
3619 | 3620 | ||
3620 | bool tagcache_is_initialized(void) | 3621 | bool tagcache_is_initialized(void) |
diff --git a/firmware/backlight.c b/firmware/backlight.c index bf88cbe9bc..4e76072822 100644 --- a/firmware/backlight.c +++ b/firmware/backlight.c | |||
@@ -618,12 +618,13 @@ static void backlight_tick(void) | |||
618 | 618 | ||
619 | void backlight_init(void) | 619 | void backlight_init(void) |
620 | { | 620 | { |
621 | queue_init(&backlight_queue); | 621 | queue_init(&backlight_queue, true); |
622 | #ifdef X5_BACKLIGHT_SHUTDOWN | 622 | #ifdef X5_BACKLIGHT_SHUTDOWN |
623 | backlight_thread_id = | 623 | backlight_thread_id = |
624 | #endif | 624 | #endif |
625 | create_thread(backlight_thread, backlight_stack, | 625 | create_thread(backlight_thread, backlight_stack, |
626 | sizeof(backlight_stack), backlight_thread_name); | 626 | sizeof(backlight_stack), backlight_thread_name |
627 | IF_PRIO(, PRIORITY_SYSTEM)); | ||
627 | tick_add_task(backlight_tick); | 628 | tick_add_task(backlight_tick); |
628 | #ifdef SIMULATOR | 629 | #ifdef SIMULATOR |
629 | /* do nothing */ | 630 | /* do nothing */ |
diff --git a/firmware/buffer.c b/firmware/buffer.c index 1eaff33de1..6af8eb9432 100644 --- a/firmware/buffer.c +++ b/firmware/buffer.c | |||
@@ -40,7 +40,9 @@ void *buffer_alloc(size_t size) | |||
40 | void *retval = audiobuf; | 40 | void *retval = audiobuf; |
41 | 41 | ||
42 | audiobuf += size; | 42 | audiobuf += size; |
43 | /* 32-bit aligned */; | 43 | /* 32-bit aligned */ |
44 | audiobuf = (void *)(((unsigned long)audiobuf + 3) & ~3); | 44 | audiobuf = (void *)(((unsigned long)audiobuf + 3) & ~3); |
45 | |||
45 | return retval; | 46 | return retval; |
46 | } | 47 | } |
48 | |||
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index 17033e1827..0bdd0657bd 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c | |||
@@ -690,9 +690,9 @@ void dircache_init(void) | |||
690 | opendirs[i].secondary_entry.d_name = buffer_alloc(MAX_PATH); | 690 | opendirs[i].secondary_entry.d_name = buffer_alloc(MAX_PATH); |
691 | } | 691 | } |
692 | 692 | ||
693 | queue_init(&dircache_queue); | 693 | queue_init(&dircache_queue, true); |
694 | create_thread(dircache_thread, dircache_stack, | 694 | create_thread(dircache_thread, dircache_stack, |
695 | sizeof(dircache_stack), dircache_thread_name); | 695 | sizeof(dircache_stack), dircache_thread_name IF_PRIO(, PRIORITY_BACKGROUND)); |
696 | } | 696 | } |
697 | 697 | ||
698 | /** | 698 | /** |
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 8593eebea1..f57088504b 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -1932,11 +1932,12 @@ int ata_init(void) | |||
1932 | if (rc) | 1932 | if (rc) |
1933 | return -60 + rc; | 1933 | return -60 + rc; |
1934 | 1934 | ||
1935 | queue_init(&ata_queue); | 1935 | queue_init(&ata_queue, true); |
1936 | 1936 | ||
1937 | last_disk_activity = current_tick; | 1937 | last_disk_activity = current_tick; |
1938 | create_thread(ata_thread, ata_stack, | 1938 | create_thread(ata_thread, ata_stack, |
1939 | sizeof(ata_stack), ata_thread_name); | 1939 | sizeof(ata_stack), ata_thread_name |
1940 | IF_PRIO(, PRIORITY_SYSTEM)); | ||
1940 | initialized = true; | 1941 | initialized = true; |
1941 | 1942 | ||
1942 | } | 1943 | } |
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c index b2e79c419a..6303ca2851 100644 --- a/firmware/drivers/ata_mmc.c +++ b/firmware/drivers/ata_mmc.c | |||
@@ -1182,9 +1182,9 @@ int ata_init(void) | |||
1182 | if (!last_mmc_status) | 1182 | if (!last_mmc_status) |
1183 | mmc_status = MMC_UNTOUCHED; | 1183 | mmc_status = MMC_UNTOUCHED; |
1184 | #ifdef HAVE_HOTSWAP | 1184 | #ifdef HAVE_HOTSWAP |
1185 | queue_init(&mmc_queue); | 1185 | queue_init(&mmc_queue, true); |
1186 | create_thread(mmc_thread, mmc_stack, | 1186 | create_thread(mmc_thread, mmc_stack, |
1187 | sizeof(mmc_stack), mmc_thread_name); | 1187 | sizeof(mmc_stack), mmc_thread_name IF_PRIO(, PRIORITY_SYSTEM)); |
1188 | #endif | 1188 | #endif |
1189 | tick_add_task(mmc_tick); | 1189 | tick_add_task(mmc_tick); |
1190 | initialized = true; | 1190 | initialized = true; |
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c index daad4f17de..6536a34037 100644 --- a/firmware/drivers/button.c +++ b/firmware/drivers/button.c | |||
@@ -674,7 +674,7 @@ void button_init(void) | |||
674 | GPIOA_INT_CLR = GPIOA_INT_STAT; | 674 | GPIOA_INT_CLR = GPIOA_INT_STAT; |
675 | GPIOA_INT_EN = 0xff; | 675 | GPIOA_INT_EN = 0xff; |
676 | #endif /* CONFIG_KEYPAD */ | 676 | #endif /* CONFIG_KEYPAD */ |
677 | queue_init(&button_queue); | 677 | queue_init(&button_queue, true); |
678 | button_read(); | 678 | button_read(); |
679 | lastbtn = button_read(); | 679 | lastbtn = button_read(); |
680 | tick_add_task(button_tick); | 680 | tick_add_task(button_tick); |
diff --git a/firmware/drivers/fmradio_i2c.c b/firmware/drivers/fmradio_i2c.c index 6f87e15b3e..62761b3aa7 100644 --- a/firmware/drivers/fmradio_i2c.c +++ b/firmware/drivers/fmradio_i2c.c | |||
@@ -317,8 +317,7 @@ static void fmradio_i2c_ack(int bit) | |||
317 | 317 | ||
318 | SCL_INPUT; /* Set the clock to input */ | 318 | SCL_INPUT; /* Set the clock to input */ |
319 | while(!SCL) /* and wait for the slave to release it */ | 319 | while(!SCL) /* and wait for the slave to release it */ |
320 | sleep_thread(); | 320 | sleep_thread(0); |
321 | wake_up_thread(); | ||
322 | 321 | ||
323 | DELAY; | 322 | DELAY; |
324 | SCL_OUTPUT; | 323 | SCL_OUTPUT; |
@@ -337,8 +336,7 @@ static int fmradio_i2c_getack(void) | |||
337 | SDA_INPUT; /* And set to input */ | 336 | SDA_INPUT; /* And set to input */ |
338 | SCL_INPUT; /* Set the clock to input */ | 337 | SCL_INPUT; /* Set the clock to input */ |
339 | while(!SCL) /* and wait for the slave to release it */ | 338 | while(!SCL) /* and wait for the slave to release it */ |
340 | sleep_thread(); | 339 | sleep_thread(0); |
341 | wake_up_thread(); | ||
342 | 340 | ||
343 | if (SDA) | 341 | if (SDA) |
344 | /* ack failed */ | 342 | /* ack failed */ |
diff --git a/firmware/drivers/i2c.c b/firmware/drivers/i2c.c index 71cb9cf8b0..2b439c23ad 100644 --- a/firmware/drivers/i2c.c +++ b/firmware/drivers/i2c.c | |||
@@ -145,8 +145,7 @@ void i2c_ack(int bit) | |||
145 | 145 | ||
146 | SCL_INPUT; /* Set the clock to input */ | 146 | SCL_INPUT; /* Set the clock to input */ |
147 | while(!SCL) /* and wait for the MAS to release it */ | 147 | while(!SCL) /* and wait for the MAS to release it */ |
148 | sleep_thread(); | 148 | sleep_thread(1); |
149 | wake_up_thread(); | ||
150 | 149 | ||
151 | DELAY; | 150 | DELAY; |
152 | SCL_OUTPUT; | 151 | SCL_OUTPUT; |
@@ -168,8 +167,7 @@ int i2c_getack(void) | |||
168 | SDA_INPUT; /* And set to input */ | 167 | SDA_INPUT; /* And set to input */ |
169 | SCL_INPUT; /* Set the clock to input */ | 168 | SCL_INPUT; /* Set the clock to input */ |
170 | while(!SCL) /* and wait for the MAS to release it */ | 169 | while(!SCL) /* and wait for the MAS to release it */ |
171 | sleep_thread(); | 170 | sleep_thread(1); |
172 | wake_up_thread(); | ||
173 | 171 | ||
174 | if (SDA) | 172 | if (SDA) |
175 | /* ack failed */ | 173 | /* ack failed */ |
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c index e6ae28bc19..47c02ea7b7 100644 --- a/firmware/drivers/lcd-16bit.c +++ b/firmware/drivers/lcd-16bit.c | |||
@@ -79,7 +79,7 @@ void lcd_init(void) | |||
79 | /* Call device specific init */ | 79 | /* Call device specific init */ |
80 | lcd_init_device(); | 80 | lcd_init_device(); |
81 | create_thread(scroll_thread, scroll_stack, | 81 | create_thread(scroll_thread, scroll_stack, |
82 | sizeof(scroll_stack), scroll_name); | 82 | sizeof(scroll_stack), scroll_name, PRIORITY_SYSTEM); |
83 | } | 83 | } |
84 | 84 | ||
85 | /*** parameter handling ***/ | 85 | /*** parameter handling ***/ |
diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c index 33f483d38d..dc49a37c8a 100644 --- a/firmware/drivers/lcd-2bit-horz.c +++ b/firmware/drivers/lcd-2bit-horz.c | |||
@@ -76,7 +76,7 @@ void lcd_init(void) | |||
76 | /* Call device specific init */ | 76 | /* Call device specific init */ |
77 | lcd_init_device(); | 77 | lcd_init_device(); |
78 | create_thread(scroll_thread, scroll_stack, | 78 | create_thread(scroll_thread, scroll_stack, |
79 | sizeof(scroll_stack), scroll_name); | 79 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM)); |
80 | } | 80 | } |
81 | 81 | ||
82 | /*** parameter handling ***/ | 82 | /*** parameter handling ***/ |
diff --git a/firmware/drivers/lcd-h100-remote.c b/firmware/drivers/lcd-h100-remote.c index ed5816cebf..5db6d548ff 100644 --- a/firmware/drivers/lcd-h100-remote.c +++ b/firmware/drivers/lcd-h100-remote.c | |||
@@ -573,7 +573,7 @@ static void remote_tick(void) | |||
573 | void lcd_remote_init(void) | 573 | void lcd_remote_init(void) |
574 | { | 574 | { |
575 | create_thread(scroll_thread, scroll_stack, | 575 | create_thread(scroll_thread, scroll_stack, |
576 | sizeof(scroll_stack), scroll_name); | 576 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM)); |
577 | } | 577 | } |
578 | #else /* !SIMULATOR */ | 578 | #else /* !SIMULATOR */ |
579 | 579 | ||
@@ -601,10 +601,11 @@ void lcd_remote_init(void) | |||
601 | #endif | 601 | #endif |
602 | lcd_remote_clear_display(); | 602 | lcd_remote_clear_display(); |
603 | 603 | ||
604 | queue_clear(&remote_scroll_queue); /* no queue_init() -- private queue */ | 604 | /* private queue */ |
605 | queue_init(&remote_scroll_queue, false); | ||
605 | tick_add_task(remote_tick); | 606 | tick_add_task(remote_tick); |
606 | create_thread(scroll_thread, scroll_stack, | 607 | create_thread(scroll_thread, scroll_stack, |
607 | sizeof(scroll_stack), scroll_name); | 608 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM)); |
608 | } | 609 | } |
609 | 610 | ||
610 | /*** update functions ***/ | 611 | /*** update functions ***/ |
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c index 8407876d34..ada6f29216 100644 --- a/firmware/drivers/lcd-h100.c +++ b/firmware/drivers/lcd-h100.c | |||
@@ -144,7 +144,7 @@ void lcd_set_flip(bool yesno) | |||
144 | void lcd_init(void) | 144 | void lcd_init(void) |
145 | { | 145 | { |
146 | create_thread(scroll_thread, scroll_stack, | 146 | create_thread(scroll_thread, scroll_stack, |
147 | sizeof(scroll_stack), scroll_name); | 147 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM)); |
148 | } | 148 | } |
149 | #else | 149 | #else |
150 | 150 | ||
@@ -193,7 +193,7 @@ void lcd_init(void) | |||
193 | lcd_write_command(LCD_CNTL_ON_OFF | 1); /* LCD ON */ | 193 | lcd_write_command(LCD_CNTL_ON_OFF | 1); /* LCD ON */ |
194 | 194 | ||
195 | create_thread(scroll_thread, scroll_stack, | 195 | create_thread(scroll_thread, scroll_stack, |
196 | sizeof(scroll_stack), scroll_name); | 196 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM)); |
197 | } | 197 | } |
198 | 198 | ||
199 | /*** update functions ***/ | 199 | /*** update functions ***/ |
diff --git a/firmware/drivers/lcd-player.c b/firmware/drivers/lcd-player.c index 16012470fa..050258d1f8 100644 --- a/firmware/drivers/lcd-player.c +++ b/firmware/drivers/lcd-player.c | |||
@@ -610,7 +610,7 @@ void lcd_init (void) | |||
610 | lcd_set_contrast(lcd_default_contrast()); | 610 | lcd_set_contrast(lcd_default_contrast()); |
611 | 611 | ||
612 | create_thread(scroll_thread, scroll_stack, | 612 | create_thread(scroll_thread, scroll_stack, |
613 | sizeof(scroll_stack), scroll_name); | 613 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM)); |
614 | } | 614 | } |
615 | 615 | ||
616 | void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */ | 616 | void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */ |
diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c index 1987d9a3ed..e74cad7f03 100644 --- a/firmware/drivers/lcd-recorder.c +++ b/firmware/drivers/lcd-recorder.c | |||
@@ -232,7 +232,7 @@ void lcd_set_flip(bool yesno) | |||
232 | void lcd_init(void) | 232 | void lcd_init(void) |
233 | { | 233 | { |
234 | create_thread(scroll_thread, scroll_stack, | 234 | create_thread(scroll_thread, scroll_stack, |
235 | sizeof(scroll_stack), scroll_name); | 235 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM)); |
236 | } | 236 | } |
237 | #else | 237 | #else |
238 | 238 | ||
@@ -278,7 +278,7 @@ void lcd_init(void) | |||
278 | lcd_update(); | 278 | lcd_update(); |
279 | 279 | ||
280 | create_thread(scroll_thread, scroll_stack, | 280 | create_thread(scroll_thread, scroll_stack, |
281 | sizeof(scroll_stack), scroll_name); | 281 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM)); |
282 | } | 282 | } |
283 | 283 | ||
284 | /*** Update functions ***/ | 284 | /*** Update functions ***/ |
diff --git a/firmware/drivers/lcd-remote-2bit-vi.c b/firmware/drivers/lcd-remote-2bit-vi.c index 48f8b8a25f..bae2824050 100755 --- a/firmware/drivers/lcd-remote-2bit-vi.c +++ b/firmware/drivers/lcd-remote-2bit-vi.c | |||
@@ -1167,7 +1167,7 @@ static void scroll_thread(void) | |||
1167 | void lcd_remote_init(void) | 1167 | void lcd_remote_init(void) |
1168 | { | 1168 | { |
1169 | create_thread(scroll_thread, scroll_stack, | 1169 | create_thread(scroll_thread, scroll_stack, |
1170 | sizeof(scroll_stack), scroll_name); | 1170 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM)); |
1171 | } | 1171 | } |
1172 | #else | 1172 | #else |
1173 | void lcd_remote_init(void) | 1173 | void lcd_remote_init(void) |
@@ -1176,9 +1176,10 @@ void lcd_remote_init(void) | |||
1176 | lcd_remote_init_device(); | 1176 | lcd_remote_init_device(); |
1177 | 1177 | ||
1178 | lcd_remote_clear_display(); | 1178 | lcd_remote_clear_display(); |
1179 | queue_clear(&remote_scroll_queue); /* no queue_init() -- private queue */ | 1179 | /* private queue */ |
1180 | queue_init(&remote_scroll_queue, false); | ||
1180 | tick_add_task(remote_tick); | 1181 | tick_add_task(remote_tick); |
1181 | create_thread(scroll_thread, scroll_stack, | 1182 | create_thread(scroll_thread, scroll_stack, |
1182 | sizeof(scroll_stack), scroll_name); | 1183 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_SYSTEM)); |
1183 | } | 1184 | } |
1184 | #endif | 1185 | #endif |
diff --git a/firmware/export/config.h b/firmware/export/config.h index 18adaeeca2..1b756cc6bd 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h | |||
@@ -216,8 +216,12 @@ | |||
216 | /* Enable the directory cache and tagcache in RAM if we have | 216 | /* Enable the directory cache and tagcache in RAM if we have |
217 | * plenty of RAM. Both features can be enabled independently. */ | 217 | * plenty of RAM. Both features can be enabled independently. */ |
218 | #if (MEMORYSIZE > 8 || MEM > 8) && !defined(BOOTLOADER) | 218 | #if (MEMORYSIZE > 8 || MEM > 8) && !defined(BOOTLOADER) |
219 | #define HAVE_DIRCACHE 1 | 219 | #define HAVE_DIRCACHE |
220 | #define HAVE_TC_RAMCACHE 1 | 220 | #define HAVE_TC_RAMCACHE |
221 | #endif | ||
222 | |||
223 | #if (CONFIG_CODEC == SWCODEC) && !defined(SIMULATOR) && !defined(BOOTLOADER) | ||
224 | #define HAVE_PRIORITY_SCHEDULING | ||
221 | #endif | 225 | #endif |
222 | 226 | ||
223 | /* define for all cpus from coldfire family */ | 227 | /* define for all cpus from coldfire family */ |
diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h index 26b1cbe2e7..482516b9dc 100644 --- a/firmware/export/kernel.h +++ b/firmware/export/kernel.h | |||
@@ -56,12 +56,14 @@ struct event | |||
56 | struct event_queue | 56 | struct event_queue |
57 | { | 57 | { |
58 | struct event events[QUEUE_LENGTH]; | 58 | struct event events[QUEUE_LENGTH]; |
59 | struct thread_entry *thread; | ||
59 | unsigned int read; | 60 | unsigned int read; |
60 | unsigned int write; | 61 | unsigned int write; |
61 | }; | 62 | }; |
62 | 63 | ||
63 | struct mutex | 64 | struct mutex |
64 | { | 65 | { |
66 | struct thread_entry *thread; | ||
65 | bool locked; | 67 | bool locked; |
66 | }; | 68 | }; |
67 | 69 | ||
@@ -85,7 +87,7 @@ extern void sleep(int ticks); | |||
85 | int tick_add_task(void (*f)(void)); | 87 | int tick_add_task(void (*f)(void)); |
86 | int tick_remove_task(void (*f)(void)); | 88 | int tick_remove_task(void (*f)(void)); |
87 | 89 | ||
88 | extern void queue_init(struct event_queue *q); | 90 | extern void queue_init(struct event_queue *q, bool register_queue); |
89 | extern void queue_delete(struct event_queue *q); | 91 | extern void queue_delete(struct event_queue *q); |
90 | extern void queue_wait(struct event_queue *q, struct event *ev); | 92 | extern void queue_wait(struct event_queue *q, struct event *ev); |
91 | extern void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks); | 93 | extern void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks); |
diff --git a/firmware/export/thread.h b/firmware/export/thread.h index e102997dae..7e053bc507 100644 --- a/firmware/export/thread.h +++ b/firmware/export/thread.h | |||
@@ -21,8 +21,24 @@ | |||
21 | 21 | ||
22 | #include <stdbool.h> | 22 | #include <stdbool.h> |
23 | 23 | ||
24 | /* Priority scheduling (when enabled with HAVE_PRIORITY_SCHEDULING) works | ||
25 | * by giving high priority threads more CPU time than less priority threads | ||
26 | * when they need it. | ||
27 | * | ||
28 | * If software playback codec pcm buffer is going down to critical, codec | ||
29 | * can change it own priority to REALTIME to override user interface and | ||
30 | * prevent playback skipping. | ||
31 | */ | ||
32 | #define PRIORITY_REALTIME 1 | ||
33 | #define PRIORITY_USER_INTERFACE 4 /* The main thread */ | ||
34 | #define PRIORITY_RECORDING 4 /* Recording thread */ | ||
35 | #define PRIORITY_PLAYBACK 4 /* or REALTIME when needed */ | ||
36 | #define PRIORITY_BUFFERING 4 /* Codec buffering thread */ | ||
37 | #define PRIORITY_SYSTEM 6 /* All other firmware threads */ | ||
38 | #define PRIORITY_BACKGROUND 8 /* Normal application threads */ | ||
39 | |||
24 | #if CONFIG_CODEC == SWCODEC | 40 | #if CONFIG_CODEC == SWCODEC |
25 | #define MAXTHREADS 16 | 41 | #define MAXTHREADS 15 |
26 | #else | 42 | #else |
27 | #define MAXTHREADS 11 | 43 | #define MAXTHREADS 11 |
28 | #endif | 44 | #endif |
@@ -32,7 +48,7 @@ | |||
32 | #ifndef SIMULATOR | 48 | #ifndef SIMULATOR |
33 | /* Need to keep structures inside the header file because debug_menu | 49 | /* Need to keep structures inside the header file because debug_menu |
34 | * needs them. */ | 50 | * needs them. */ |
35 | #ifdef CPU_COLDFIRE | 51 | # ifdef CPU_COLDFIRE |
36 | struct regs | 52 | struct regs |
37 | { | 53 | { |
38 | unsigned int macsr; /* EMAC status register */ | 54 | unsigned int macsr; /* EMAC status register */ |
@@ -41,7 +57,7 @@ struct regs | |||
41 | void *sp; /* Stack pointer (a7) */ | 57 | void *sp; /* Stack pointer (a7) */ |
42 | void *start; /* Thread start address, or NULL when started */ | 58 | void *start; /* Thread start address, or NULL when started */ |
43 | }; | 59 | }; |
44 | #elif CONFIG_CPU == SH7034 | 60 | # elif CONFIG_CPU == SH7034 |
45 | struct regs | 61 | struct regs |
46 | { | 62 | { |
47 | unsigned int r[7]; /* Registers r8 thru r14 */ | 63 | unsigned int r[7]; /* Registers r8 thru r14 */ |
@@ -49,7 +65,7 @@ struct regs | |||
49 | void *pr; /* Procedure register */ | 65 | void *pr; /* Procedure register */ |
50 | void *start; /* Thread start address, or NULL when started */ | 66 | void *start; /* Thread start address, or NULL when started */ |
51 | }; | 67 | }; |
52 | #elif defined(CPU_ARM) | 68 | # elif defined(CPU_ARM) |
53 | struct regs | 69 | struct regs |
54 | { | 70 | { |
55 | unsigned int r[8]; /* Registers r4-r11 */ | 71 | unsigned int r[8]; /* Registers r4-r11 */ |
@@ -57,42 +73,72 @@ struct regs | |||
57 | unsigned int lr; /* r14 (lr) */ | 73 | unsigned int lr; /* r14 (lr) */ |
58 | void *start; /* Thread start address, or NULL when started */ | 74 | void *start; /* Thread start address, or NULL when started */ |
59 | }; | 75 | }; |
60 | #elif CONFIG_CPU == TCC730 | 76 | # elif CONFIG_CPU == TCC730 |
61 | struct regs | 77 | struct regs |
62 | { | 78 | { |
63 | void *sp; /* Stack pointer (a15) */ | 79 | void *sp; /* Stack pointer (a15) */ |
64 | void *start; /* Thread start address */ | 80 | void *start; /* Thread start address */ |
65 | int started; /* 0 when not started */ | 81 | int started; /* 0 when not started */ |
66 | }; | 82 | }; |
67 | #endif | 83 | # endif |
84 | |||
85 | #endif /* !SIMULATOR */ | ||
86 | |||
87 | #define STATE_RUNNING 0 | ||
88 | #define STATE_BLOCKED 1 | ||
89 | #define STATE_SLEEPING 2 | ||
90 | #define STATE_BLOCKED_W_TMO 3 | ||
91 | |||
92 | #define GET_STATE_ARG(state) (state & 0x3FFFFFFF) | ||
93 | #define GET_STATE(state) ((state >> 30) & 3) | ||
94 | #define SET_STATE(state,arg) ((state << 30) | (arg)) | ||
68 | 95 | ||
69 | struct thread_entry { | 96 | struct thread_entry { |
97 | #ifndef SIMULATOR | ||
70 | struct regs context; | 98 | struct regs context; |
99 | #endif | ||
71 | const char *name; | 100 | const char *name; |
72 | void *stack; | 101 | void *stack; |
73 | int stack_size; | 102 | unsigned long statearg; |
103 | unsigned short stack_size; | ||
104 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
105 | unsigned short priority; | ||
106 | long last_run; | ||
107 | #endif | ||
108 | struct thread_entry *next, *prev; | ||
74 | }; | 109 | }; |
75 | 110 | ||
76 | struct core_entry { | 111 | struct core_entry { |
77 | int num_threads; | ||
78 | volatile int num_sleepers; | ||
79 | int current_thread; | ||
80 | struct thread_entry threads[MAXTHREADS]; | 112 | struct thread_entry threads[MAXTHREADS]; |
113 | struct thread_entry *running; | ||
114 | struct thread_entry *sleeping; | ||
81 | }; | 115 | }; |
116 | |||
117 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
118 | #define IF_PRIO(empty, type) , type | ||
119 | #else | ||
120 | #define IF_PRIO(empty, type) | ||
82 | #endif | 121 | #endif |
83 | 122 | ||
84 | int create_thread(void (*function)(void), void* stack, int stack_size, | 123 | struct thread_entry* |
85 | const char *name); | 124 | create_thread(void (*function)(void), void* stack, int stack_size, |
86 | int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size, | 125 | const char *name IF_PRIO(, int priority)); |
87 | const char *name); | 126 | |
88 | void remove_thread(int threadnum); | 127 | struct thread_entry* |
89 | void remove_thread_on_core(unsigned int core, int threadnum); | 128 | create_thread_on_core(unsigned int core, void (*function)(void), |
90 | void switch_thread(void); | 129 | void* stack, int stack_size, |
91 | void sleep_thread(void); | 130 | const char *name |
92 | void wake_up_thread(void); | 131 | IF_PRIO(, int priority)); |
132 | |||
133 | void remove_thread(struct thread_entry *thread); | ||
134 | void switch_thread(bool save_context, struct thread_entry **blocked_list); | ||
135 | void sleep_thread(int ticks); | ||
136 | void block_thread(struct thread_entry **thread, int timeout); | ||
137 | void wakeup_thread(struct thread_entry **thread); | ||
138 | void thread_set_priority(struct thread_entry *thread, int priority); | ||
93 | void init_threads(void); | 139 | void init_threads(void); |
94 | int thread_stack_usage(int threadnum); | 140 | int thread_stack_usage(const struct thread_entry *thread); |
95 | int thread_stack_usage_on_core(unsigned int core, int threadnum); | 141 | int thread_get_status(const struct thread_entry *thread); |
96 | #ifdef RB_PROFILE | 142 | #ifdef RB_PROFILE |
97 | void profile_thread(void); | 143 | void profile_thread(void); |
98 | #endif | 144 | #endif |
diff --git a/firmware/kernel.c b/firmware/kernel.c index 889f950252..4a6d61515a 100644 --- a/firmware/kernel.c +++ b/firmware/kernel.c | |||
@@ -35,7 +35,6 @@ static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); | |||
35 | static struct event_queue *all_queues[32]; | 35 | static struct event_queue *all_queues[32]; |
36 | static int num_queues; | 36 | static int num_queues; |
37 | 37 | ||
38 | void sleep(int ticks) ICODE_ATTR; | ||
39 | void queue_wait(struct event_queue *q, struct event *ev) ICODE_ATTR; | 38 | void queue_wait(struct event_queue *q, struct event *ev) ICODE_ATTR; |
40 | 39 | ||
41 | /**************************************************************************** | 40 | /**************************************************************************** |
@@ -71,13 +70,7 @@ void sleep(int ticks) | |||
71 | } while(counter > 0); | 70 | } while(counter > 0); |
72 | 71 | ||
73 | #else | 72 | #else |
74 | /* Always sleep at least 1 tick */ | 73 | sleep_thread(ticks); |
75 | int timeout = current_tick + ticks + 1; | ||
76 | |||
77 | while (TIME_BEFORE( current_tick, timeout )) { | ||
78 | sleep_thread(); | ||
79 | } | ||
80 | wake_up_thread(); | ||
81 | #endif | 74 | #endif |
82 | } | 75 | } |
83 | 76 | ||
@@ -86,21 +79,24 @@ void yield(void) | |||
86 | #if (CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022) && defined(BOOTLOADER)) | 79 | #if (CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022) && defined(BOOTLOADER)) |
87 | /* Some targets don't like yielding in the bootloader */ | 80 | /* Some targets don't like yielding in the bootloader */ |
88 | #else | 81 | #else |
89 | switch_thread(); | 82 | switch_thread(true, NULL); |
90 | wake_up_thread(); | ||
91 | #endif | 83 | #endif |
92 | } | 84 | } |
93 | 85 | ||
94 | /**************************************************************************** | 86 | /**************************************************************************** |
95 | * Queue handling stuff | 87 | * Queue handling stuff |
96 | ****************************************************************************/ | 88 | ****************************************************************************/ |
97 | void queue_init(struct event_queue *q) | 89 | void queue_init(struct event_queue *q, bool register_queue) |
98 | { | 90 | { |
99 | q->read = 0; | 91 | q->read = 0; |
100 | q->write = 0; | 92 | q->write = 0; |
101 | 93 | q->thread = NULL; | |
102 | /* Add it to the all_queues array */ | 94 | |
103 | all_queues[num_queues++] = q; | 95 | if (register_queue) |
96 | { | ||
97 | /* Add it to the all_queues array */ | ||
98 | all_queues[num_queues++] = q; | ||
99 | } | ||
104 | } | 100 | } |
105 | 101 | ||
106 | void queue_delete(struct event_queue *q) | 102 | void queue_delete(struct event_queue *q) |
@@ -108,6 +104,8 @@ void queue_delete(struct event_queue *q) | |||
108 | int i; | 104 | int i; |
109 | bool found = false; | 105 | bool found = false; |
110 | 106 | ||
107 | wakeup_thread(&q->thread); | ||
108 | |||
111 | /* Find the queue to be deleted */ | 109 | /* Find the queue to be deleted */ |
112 | for(i = 0;i < num_queues;i++) | 110 | for(i = 0;i < num_queues;i++) |
113 | { | 111 | { |
@@ -132,26 +130,22 @@ void queue_delete(struct event_queue *q) | |||
132 | 130 | ||
133 | void queue_wait(struct event_queue *q, struct event *ev) | 131 | void queue_wait(struct event_queue *q, struct event *ev) |
134 | { | 132 | { |
135 | while(q->read == q->write) | 133 | if (q->read == q->write) |
136 | { | 134 | { |
137 | sleep_thread(); | 135 | block_thread(&q->thread, 0); |
138 | } | 136 | } |
139 | wake_up_thread(); | ||
140 | 137 | ||
141 | *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; | 138 | *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; |
142 | } | 139 | } |
143 | 140 | ||
144 | void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) | 141 | void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) |
145 | { | 142 | { |
146 | unsigned int timeout = current_tick + ticks; | 143 | if (q->read == q->write && ticks > 0) |
147 | |||
148 | while(q->read == q->write && TIME_BEFORE( current_tick, timeout )) | ||
149 | { | 144 | { |
150 | sleep_thread(); | 145 | block_thread(&q->thread, ticks); |
151 | } | 146 | } |
152 | wake_up_thread(); | ||
153 | 147 | ||
154 | if(q->read != q->write) | 148 | if (q->read != q->write) |
155 | { | 149 | { |
156 | *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; | 150 | *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; |
157 | } | 151 | } |
@@ -171,6 +165,9 @@ void queue_post(struct event_queue *q, long id, void *data) | |||
171 | 165 | ||
172 | q->events[wr].id = id; | 166 | q->events[wr].id = id; |
173 | q->events[wr].data = data; | 167 | q->events[wr].data = data; |
168 | |||
169 | wakeup_thread(&q->thread); | ||
170 | |||
174 | set_irq_level(oldlevel); | 171 | set_irq_level(oldlevel); |
175 | } | 172 | } |
176 | 173 | ||
@@ -250,7 +247,6 @@ void IMIA0(void) | |||
250 | } | 247 | } |
251 | 248 | ||
252 | current_tick++; | 249 | current_tick++; |
253 | wake_up_thread(); | ||
254 | 250 | ||
255 | TSR0 &= ~0x01; | 251 | TSR0 &= ~0x01; |
256 | } | 252 | } |
@@ -301,7 +297,6 @@ void TIMER0(void) | |||
301 | } | 297 | } |
302 | 298 | ||
303 | current_tick++; | 299 | current_tick++; |
304 | wake_up_thread(); | ||
305 | 300 | ||
306 | TER0 = 0xff; /* Clear all events */ | 301 | TER0 = 0xff; /* Clear all events */ |
307 | } | 302 | } |
@@ -330,7 +325,6 @@ void TIMER0(void) | |||
330 | } | 325 | } |
331 | 326 | ||
332 | current_tick++; | 327 | current_tick++; |
333 | wake_up_thread(); | ||
334 | 328 | ||
335 | /* re-enable timer by clearing the counter */ | 329 | /* re-enable timer by clearing the counter */ |
336 | TACON |= 0x80; | 330 | TACON |= 0x80; |
@@ -382,7 +376,6 @@ void TIMER1(void) | |||
382 | } | 376 | } |
383 | 377 | ||
384 | current_tick++; | 378 | current_tick++; |
385 | wake_up_thread(); | ||
386 | } | 379 | } |
387 | #endif | 380 | #endif |
388 | 381 | ||
@@ -415,7 +408,6 @@ void timer_handler(void) | |||
415 | } | 408 | } |
416 | 409 | ||
417 | current_tick++; | 410 | current_tick++; |
418 | wake_up_thread(); | ||
419 | 411 | ||
420 | TIMERR0C = 1; | 412 | TIMERR0C = 1; |
421 | } | 413 | } |
@@ -513,22 +505,27 @@ int tick_remove_task(void (*f)(void)) | |||
513 | void mutex_init(struct mutex *m) | 505 | void mutex_init(struct mutex *m) |
514 | { | 506 | { |
515 | m->locked = false; | 507 | m->locked = false; |
508 | m->thread = NULL; | ||
516 | } | 509 | } |
517 | 510 | ||
518 | void mutex_lock(struct mutex *m) | 511 | void mutex_lock(struct mutex *m) |
519 | { | 512 | { |
520 | /* Wait until the lock is open... */ | 513 | if (m->locked) |
521 | while(m->locked) | 514 | { |
522 | sleep_thread(); | 515 | /* Wait until the lock is open... */ |
523 | wake_up_thread(); | 516 | block_thread(&m->thread, 0); |
524 | 517 | } | |
518 | |||
525 | /* ...and lock it */ | 519 | /* ...and lock it */ |
526 | m->locked = true; | 520 | m->locked = true; |
527 | } | 521 | } |
528 | 522 | ||
529 | void mutex_unlock(struct mutex *m) | 523 | void mutex_unlock(struct mutex *m) |
530 | { | 524 | { |
531 | m->locked = false; | 525 | if (m->thread == NULL) |
526 | m->locked = false; | ||
527 | else | ||
528 | wakeup_thread(&m->thread); | ||
532 | } | 529 | } |
533 | 530 | ||
534 | #endif | 531 | #endif |
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index df0cbbad12..61b0a22d87 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -761,7 +761,6 @@ void rec_tick(void) | |||
761 | { | 761 | { |
762 | prerecord_timeout = current_tick + HZ; | 762 | prerecord_timeout = current_tick + HZ; |
763 | queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0); | 763 | queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0); |
764 | wake_up_thread(); | ||
765 | } | 764 | } |
766 | } | 765 | } |
767 | else | 766 | else |
@@ -773,7 +772,6 @@ void rec_tick(void) | |||
773 | { | 772 | { |
774 | saving_status = BUFFER_FULL; | 773 | saving_status = BUFFER_FULL; |
775 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | 774 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); |
776 | wake_up_thread(); | ||
777 | } | 775 | } |
778 | } | 776 | } |
779 | } | 777 | } |
@@ -894,8 +892,6 @@ static void transfer_end(unsigned char** ppbuf, int* psize) | |||
894 | *psize = 0; /* no more transfer */ | 892 | *psize = 0; /* no more transfer */ |
895 | } | 893 | } |
896 | } | 894 | } |
897 | |||
898 | wake_up_thread(); | ||
899 | } | 895 | } |
900 | 896 | ||
901 | static struct trackdata *add_track_to_tag_list(const char *filename) | 897 | static struct trackdata *add_track_to_tag_list(const char *filename) |
@@ -2119,8 +2115,7 @@ void audio_init_playback(void) | |||
2119 | queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL); | 2115 | queue_post(&mpeg_queue, MPEG_INIT_PLAYBACK, NULL); |
2120 | 2116 | ||
2121 | while(!init_playback_done) | 2117 | while(!init_playback_done) |
2122 | sleep_thread(); | 2118 | sleep_thread(1); |
2123 | wake_up_thread(); | ||
2124 | } | 2119 | } |
2125 | 2120 | ||
2126 | 2121 | ||
@@ -2134,8 +2129,7 @@ void audio_init_recording(unsigned int buffer_offset) | |||
2134 | queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL); | 2129 | queue_post(&mpeg_queue, MPEG_INIT_RECORDING, NULL); |
2135 | 2130 | ||
2136 | while(!init_recording_done) | 2131 | while(!init_recording_done) |
2137 | sleep_thread(); | 2132 | sleep_thread(1); |
2138 | wake_up_thread(); | ||
2139 | } | 2133 | } |
2140 | 2134 | ||
2141 | static void init_recording(void) | 2135 | static void init_recording(void) |
@@ -2886,10 +2880,10 @@ void audio_init(void) | |||
2886 | 2880 | ||
2887 | #ifndef SIMULATOR | 2881 | #ifndef SIMULATOR |
2888 | audiobuflen = audiobufend - audiobuf; | 2882 | audiobuflen = audiobufend - audiobuf; |
2889 | queue_init(&mpeg_queue); | 2883 | queue_init(&mpeg_queue, true); |
2890 | #endif /* !SIMULATOR */ | 2884 | #endif /* !SIMULATOR */ |
2891 | create_thread(mpeg_thread, mpeg_stack, | 2885 | create_thread(mpeg_thread, mpeg_stack, |
2892 | sizeof(mpeg_stack), mpeg_thread_name); | 2886 | sizeof(mpeg_stack), mpeg_thread_name IF_PRIO(, PRIORITY_SYSTEM)); |
2893 | 2887 | ||
2894 | memset(trackdata, sizeof(trackdata), 0); | 2888 | memset(trackdata, sizeof(trackdata), 0); |
2895 | 2889 | ||
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c index 68fc22b937..bce6fb5f25 100644 --- a/firmware/pcm_record.c +++ b/firmware/pcm_record.c | |||
@@ -172,9 +172,9 @@ static void close_wave(void); | |||
172 | /* Creates pcmrec_thread */ | 172 | /* Creates pcmrec_thread */ |
173 | void pcm_rec_init(void) | 173 | void pcm_rec_init(void) |
174 | { | 174 | { |
175 | queue_init(&pcmrec_queue); | 175 | queue_init(&pcmrec_queue, true); |
176 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), | 176 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), |
177 | pcmrec_thread_name); | 177 | pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING)); |
178 | } | 178 | } |
179 | 179 | ||
180 | 180 | ||
@@ -196,8 +196,7 @@ void audio_init_recording(unsigned int buffer_offset) | |||
196 | queue_post(&pcmrec_queue, PCMREC_INIT, 0); | 196 | queue_post(&pcmrec_queue, PCMREC_INIT, 0); |
197 | 197 | ||
198 | while(!init_done) | 198 | while(!init_done) |
199 | sleep_thread(); | 199 | sleep_thread(1); |
200 | wake_up_thread(); | ||
201 | } | 200 | } |
202 | 201 | ||
203 | void audio_close_recording(void) | 202 | void audio_close_recording(void) |
@@ -206,8 +205,7 @@ void audio_close_recording(void) | |||
206 | queue_post(&pcmrec_queue, PCMREC_CLOSE, 0); | 205 | queue_post(&pcmrec_queue, PCMREC_CLOSE, 0); |
207 | 206 | ||
208 | while(!close_done) | 207 | while(!close_done) |
209 | sleep_thread(); | 208 | sleep_thread(1); |
210 | wake_up_thread(); | ||
211 | 209 | ||
212 | audio_remove_encoder(); | 210 | audio_remove_encoder(); |
213 | } | 211 | } |
@@ -421,8 +419,7 @@ void audio_record(const char *filename) | |||
421 | queue_post(&pcmrec_queue, PCMREC_START, 0); | 419 | queue_post(&pcmrec_queue, PCMREC_START, 0); |
422 | 420 | ||
423 | while(!record_done) | 421 | while(!record_done) |
424 | sleep_thread(); | 422 | sleep_thread(1); |
425 | wake_up_thread(); | ||
426 | } | 423 | } |
427 | 424 | ||
428 | 425 | ||
@@ -438,8 +435,7 @@ void audio_new_file(const char *filename) | |||
438 | queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0); | 435 | queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0); |
439 | 436 | ||
440 | while(!new_file_done) | 437 | while(!new_file_done) |
441 | sleep_thread(); | 438 | sleep_thread(1); |
442 | wake_up_thread(); | ||
443 | 439 | ||
444 | logf("pcm_new_file done"); | 440 | logf("pcm_new_file done"); |
445 | } | 441 | } |
@@ -459,8 +455,7 @@ void audio_stop_recording(void) | |||
459 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); | 455 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); |
460 | 456 | ||
461 | while(!stop_done) | 457 | while(!stop_done) |
462 | sleep_thread(); | 458 | sleep_thread(1); |
463 | wake_up_thread(); | ||
464 | 459 | ||
465 | logf("pcm_stop done"); | 460 | logf("pcm_stop done"); |
466 | } | 461 | } |
@@ -482,8 +477,7 @@ void audio_pause_recording(void) | |||
482 | queue_post(&pcmrec_queue, PCMREC_PAUSE, 0); | 477 | queue_post(&pcmrec_queue, PCMREC_PAUSE, 0); |
483 | 478 | ||
484 | while(!pause_done) | 479 | while(!pause_done) |
485 | sleep_thread(); | 480 | sleep_thread(1); |
486 | wake_up_thread(); | ||
487 | } | 481 | } |
488 | 482 | ||
489 | void audio_resume_recording(void) | 483 | void audio_resume_recording(void) |
@@ -498,8 +492,7 @@ void audio_resume_recording(void) | |||
498 | queue_post(&pcmrec_queue, PCMREC_RESUME, 0); | 492 | queue_post(&pcmrec_queue, PCMREC_RESUME, 0); |
499 | 493 | ||
500 | while(!resume_done) | 494 | while(!resume_done) |
501 | sleep_thread(); | 495 | sleep_thread(1); |
502 | wake_up_thread(); | ||
503 | } | 496 | } |
504 | 497 | ||
505 | /* return peaks as int, so convert from short first | 498 | /* return peaks as int, so convert from short first |
@@ -817,9 +810,8 @@ static void pcmrec_stop(void) | |||
817 | /* wait for encoding finish */ | 810 | /* wait for encoding finish */ |
818 | is_paused = true; | 811 | is_paused = true; |
819 | while(!wav_queue_empty) | 812 | while(!wav_queue_empty) |
820 | sleep_thread(); | 813 | sleep_thread(1); |
821 | 814 | ||
822 | wake_up_thread(); | ||
823 | is_recording = false; | 815 | is_recording = false; |
824 | 816 | ||
825 | /* Flush buffers to file */ | 817 | /* Flush buffers to file */ |
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index 8f832964b5..f1e1aac57f 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c | |||
@@ -998,7 +998,7 @@ void powermgmt_init(void) | |||
998 | memset(power_history, 0x00, sizeof(power_history)); | 998 | memset(power_history, 0x00, sizeof(power_history)); |
999 | 999 | ||
1000 | create_thread(power_thread, power_stack, sizeof(power_stack), | 1000 | create_thread(power_thread, power_stack, sizeof(power_stack), |
1001 | power_thread_name); | 1001 | power_thread_name IF_PRIO(, PRIORITY_SYSTEM)); |
1002 | } | 1002 | } |
1003 | 1003 | ||
1004 | #endif /* SIMULATOR */ | 1004 | #endif /* SIMULATOR */ |
diff --git a/firmware/thread.c b/firmware/thread.c index eb39c7ad32..e4dcbbcf9a 100644 --- a/firmware/thread.c +++ b/firmware/thread.c | |||
@@ -23,12 +23,18 @@ | |||
23 | #include "system.h" | 23 | #include "system.h" |
24 | #include "kernel.h" | 24 | #include "kernel.h" |
25 | #include "cpu.h" | 25 | #include "cpu.h" |
26 | 26 | #include "string.h" | |
27 | 27 | ||
28 | #define DEADBEEF ((unsigned int)0xdeadbeef) | 28 | #define DEADBEEF ((unsigned int)0xdeadbeef) |
29 | /* Cast to the the machine int type, whose size could be < 4. */ | 29 | /* Cast to the the machine int type, whose size could be < 4. */ |
30 | 30 | ||
31 | struct core_entry cores[NUM_CORES] IBSS_ATTR; | 31 | struct core_entry cores[NUM_CORES] IBSS_ATTR; |
32 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
33 | static unsigned short highest_priority IBSS_ATTR; | ||
34 | #endif | ||
35 | |||
36 | /* Define to enable additional checks for blocking violations etc. */ | ||
37 | // #define THREAD_EXTRA_CHECKS | ||
32 | 38 | ||
33 | static const char main_thread_name[] = "main"; | 39 | static const char main_thread_name[] = "main"; |
34 | 40 | ||
@@ -48,7 +54,16 @@ int *cop_stackend = stackend; | |||
48 | #endif | 54 | #endif |
49 | #endif | 55 | #endif |
50 | 56 | ||
51 | void switch_thread(void) ICODE_ATTR; | 57 | /* Conserve IRAM |
58 | static void add_to_list(struct thread_entry **list, | ||
59 | struct thread_entry *thread) ICODE_ATTR; | ||
60 | static void remove_from_list(struct thread_entry **list, | ||
61 | struct thread_entry *thread) ICODE_ATTR; | ||
62 | */ | ||
63 | |||
64 | void switch_thread(bool save_context, struct thread_entry **blocked_list) | ||
65 | ICODE_ATTR; | ||
66 | |||
52 | static inline void store_context(void* addr) __attribute__ ((always_inline)); | 67 | static inline void store_context(void* addr) __attribute__ ((always_inline)); |
53 | static inline void load_context(const void* addr) __attribute__ ((always_inline)); | 68 | static inline void load_context(const void* addr) __attribute__ ((always_inline)); |
54 | 69 | ||
@@ -219,24 +234,109 @@ static inline void load_context(const void* addr) | |||
219 | 234 | ||
220 | #endif | 235 | #endif |
221 | 236 | ||
222 | /*--------------------------------------------------------------------------- | 237 | static void add_to_list(struct thread_entry **list, |
223 | * Switch thread in round robin fashion. | 238 | struct thread_entry *thread) |
224 | *--------------------------------------------------------------------------- | ||
225 | */ | ||
226 | void switch_thread(void) | ||
227 | { | 239 | { |
228 | #ifdef RB_PROFILE | 240 | if (*list == NULL) |
229 | profile_thread_stopped(cores[CURRENT_CORE].current_thread); | 241 | { |
230 | #endif | 242 | thread->next = thread; |
231 | int current; | 243 | thread->prev = thread; |
232 | unsigned int *stackptr; | 244 | *list = thread; |
245 | } | ||
246 | else | ||
247 | { | ||
248 | /* Insert last */ | ||
249 | thread->next = *list; | ||
250 | thread->prev = (*list)->prev; | ||
251 | thread->prev->next = thread; | ||
252 | (*list)->prev = thread; | ||
253 | |||
254 | /* Insert next | ||
255 | thread->next = (*list)->next; | ||
256 | thread->prev = *list; | ||
257 | thread->next->prev = thread; | ||
258 | (*list)->next = thread; | ||
259 | */ | ||
260 | } | ||
261 | } | ||
233 | 262 | ||
234 | #ifdef SIMULATOR | 263 | static void remove_from_list(struct thread_entry **list, |
235 | /* Do nothing */ | 264 | struct thread_entry *thread) |
236 | #else | 265 | { |
237 | while (cores[CURRENT_CORE].num_sleepers == cores[CURRENT_CORE].num_threads) | 266 | if (list != NULL) |
267 | { | ||
268 | if (thread == thread->next) | ||
269 | { | ||
270 | *list = NULL; | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | if (thread == *list) | ||
275 | *list = thread->next; | ||
276 | } | ||
277 | |||
278 | /* Fix links to jump over the removed entry. */ | ||
279 | thread->prev->next = thread->next; | ||
280 | thread->next->prev = thread->prev; | ||
281 | } | ||
282 | |||
283 | /* Compiler trick: Don't declare as static to prevent putting | ||
284 | * function in IRAM. */ | ||
285 | void check_sleepers(void) | ||
286 | { | ||
287 | struct thread_entry *current, *next; | ||
288 | |||
289 | /* Check sleeping threads. */ | ||
290 | current = cores[CURRENT_CORE].sleeping; | ||
291 | if (current == NULL) | ||
292 | return ; | ||
293 | |||
294 | for (;;) | ||
295 | { | ||
296 | next = current->next; | ||
297 | |||
298 | if ((unsigned)current_tick >= GET_STATE_ARG(current->statearg)) | ||
299 | { | ||
300 | /* Sleep timeout has been reached so bring the thread | ||
301 | * back to life again. */ | ||
302 | remove_from_list(&cores[CURRENT_CORE].sleeping, current); | ||
303 | add_to_list(&cores[CURRENT_CORE].running, current); | ||
304 | |||
305 | /* If there is no more processes in the list, break the loop. */ | ||
306 | if (cores[CURRENT_CORE].sleeping == NULL) | ||
307 | break; | ||
308 | |||
309 | current = next; | ||
310 | continue; | ||
311 | } | ||
312 | |||
313 | current = next; | ||
314 | |||
315 | /* Break the loop once we have walked through the list of all | ||
316 | * sleeping processes. */ | ||
317 | if (current == cores[CURRENT_CORE].sleeping) | ||
318 | break; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | static inline void sleep_core(void) | ||
323 | { | ||
324 | static long last_tick = 0; | ||
325 | |||
326 | for (;;) | ||
238 | { | 327 | { |
239 | /* Enter sleep mode, woken up on interrupt */ | 328 | if (last_tick != current_tick) |
329 | { | ||
330 | check_sleepers(); | ||
331 | last_tick = current_tick; | ||
332 | } | ||
333 | |||
334 | /* We must sleep until there is at least one process in the list | ||
335 | * of running processes. */ | ||
336 | if (cores[CURRENT_CORE].running != NULL) | ||
337 | break; | ||
338 | |||
339 | /* Enter sleep mode to reduce power usage, woken up on interrupt */ | ||
240 | #ifdef CPU_COLDFIRE | 340 | #ifdef CPU_COLDFIRE |
241 | asm volatile ("stop #0x2000"); | 341 | asm volatile ("stop #0x2000"); |
242 | #elif CONFIG_CPU == SH7034 | 342 | #elif CONFIG_CPU == SH7034 |
@@ -257,49 +357,232 @@ void switch_thread(void) | |||
257 | CLKCON |= 2; | 357 | CLKCON |= 2; |
258 | #endif | 358 | #endif |
259 | } | 359 | } |
260 | #endif | 360 | } |
261 | current = cores[CURRENT_CORE].current_thread; | 361 | |
262 | store_context(&cores[CURRENT_CORE].threads[current].context); | 362 | #ifdef RB_PROFILE |
263 | 363 | static int get_threadnum(struct thread_entry *thread) | |
264 | #if CONFIG_CPU != TCC730 | 364 | { |
265 | /* Check if the current thread stack is overflown */ | 365 | int i; |
266 | stackptr = cores[CURRENT_CORE].threads[current].stack; | 366 | |
267 | if(stackptr[0] != DEADBEEF) | 367 | for (i = 0; i < MAXTHREADS; i++) |
268 | panicf("Stkov %s", cores[CURRENT_CORE].threads[current].name); | 368 | { |
369 | if (&cores[CURRENT_CORE].threads[i] == thread) | ||
370 | return i; | ||
371 | } | ||
372 | |||
373 | return -1; | ||
374 | } | ||
269 | #endif | 375 | #endif |
270 | 376 | ||
271 | if (++current >= cores[CURRENT_CORE].num_threads) | 377 | /* Compiler trick: Don't declare as static to prevent putting |
272 | current = 0; | 378 | * function in IRAM. */ |
379 | void change_thread_state(struct thread_entry **blocked_list) | ||
380 | { | ||
381 | struct thread_entry *old; | ||
382 | |||
383 | /* Remove the thread from the list of running threads. */ | ||
384 | old = cores[CURRENT_CORE].running; | ||
385 | remove_from_list(&cores[CURRENT_CORE].running, old); | ||
386 | |||
387 | /* And put the thread into a new list of inactive threads. */ | ||
388 | if (GET_STATE(old->statearg) == STATE_BLOCKED) | ||
389 | add_to_list(blocked_list, old); | ||
390 | else | ||
391 | add_to_list(&cores[CURRENT_CORE].sleeping, old); | ||
392 | |||
393 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
394 | /* Reset priorities */ | ||
395 | if (old->priority == highest_priority) | ||
396 | highest_priority = 100; | ||
397 | #endif | ||
398 | } | ||
273 | 399 | ||
274 | cores[CURRENT_CORE].current_thread = current; | 400 | /*--------------------------------------------------------------------------- |
275 | load_context(&cores[CURRENT_CORE].threads[current].context); | 401 | * Switch thread in round robin fashion. |
402 | *--------------------------------------------------------------------------- | ||
403 | */ | ||
404 | void switch_thread(bool save_context, struct thread_entry **blocked_list) | ||
405 | { | ||
276 | #ifdef RB_PROFILE | 406 | #ifdef RB_PROFILE |
277 | profile_thread_started(cores[CURRENT_CORE].current_thread); | 407 | profile_thread_stopped(get_threadnum(cores[CURRENT_CORE].running)); |
408 | #endif | ||
409 | unsigned int *stackptr; | ||
410 | |||
411 | #ifdef SIMULATOR | ||
412 | /* Do nothing */ | ||
413 | #else | ||
414 | |||
415 | /* Begin task switching by saving our current context so that we can | ||
416 | * restore the state of the current thread later to the point prior | ||
417 | * to this call. */ | ||
418 | if (save_context) | ||
419 | { | ||
420 | store_context(&cores[CURRENT_CORE].running->context); | ||
421 | |||
422 | # if CONFIG_CPU != TCC730 | ||
423 | /* Check if the current thread stack is overflown */ | ||
424 | stackptr = cores[CURRENT_CORE].running->stack; | ||
425 | if(stackptr[0] != DEADBEEF) | ||
426 | panicf("Stkov %s", cores[CURRENT_CORE].running->name); | ||
427 | # endif | ||
428 | |||
429 | /* Check if a thread state change has been requested. */ | ||
430 | if (cores[CURRENT_CORE].running->statearg) | ||
431 | { | ||
432 | /* Change running thread state and switch to next thread. */ | ||
433 | change_thread_state(blocked_list); | ||
434 | } | ||
435 | else | ||
436 | { | ||
437 | /* Switch to the next running thread. */ | ||
438 | cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | /* Go through the list of sleeping task to check if we need to wake up | ||
443 | * any of them due to timeout. Also puts core into sleep state until | ||
444 | * there is at least one running process again. */ | ||
445 | sleep_core(); | ||
446 | |||
447 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
448 | /* Select the new task based on priorities and the last time a process | ||
449 | * got CPU time. */ | ||
450 | for (;;) | ||
451 | { | ||
452 | int priority = cores[CURRENT_CORE].running->priority; | ||
453 | |||
454 | if (priority < highest_priority) | ||
455 | highest_priority = priority; | ||
456 | |||
457 | if (priority == highest_priority || (current_tick | ||
458 | - cores[CURRENT_CORE].running->last_run > priority * 8)) | ||
459 | { | ||
460 | break; | ||
461 | } | ||
462 | cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next; | ||
463 | } | ||
464 | |||
465 | /* Reset the value of thread's last running time to the current time. */ | ||
466 | cores[CURRENT_CORE].running->last_run = current_tick; | ||
467 | #endif | ||
468 | |||
469 | #endif | ||
470 | /* And finally give control to the next thread. */ | ||
471 | load_context(&cores[CURRENT_CORE].running->context); | ||
472 | |||
473 | #ifdef RB_PROFILE | ||
474 | profile_thread_started(get_threadnum(cores[CURRENT_CORE].running)); | ||
278 | #endif | 475 | #endif |
279 | } | 476 | } |
280 | 477 | ||
281 | void sleep_thread(void) | 478 | void sleep_thread(int ticks) |
282 | { | 479 | { |
283 | ++cores[CURRENT_CORE].num_sleepers; | 480 | /* Set the thread's new state and timeout and finally force a task switch |
284 | switch_thread(); | 481 | * so that scheduler removes thread from the list of running processes |
482 | * and puts it in list of sleeping tasks. */ | ||
483 | cores[CURRENT_CORE].running->statearg = | ||
484 | SET_STATE(STATE_SLEEPING, current_tick + ticks + 1); | ||
485 | switch_thread(true, NULL); | ||
486 | |||
487 | /* Clear all flags to indicate we are up and running again. */ | ||
488 | cores[CURRENT_CORE].running->statearg = 0; | ||
285 | } | 489 | } |
286 | 490 | ||
287 | void wake_up_thread(void) | 491 | void block_thread(struct thread_entry **list, int timeout) |
288 | { | 492 | { |
289 | cores[CURRENT_CORE].num_sleepers = 0; | 493 | struct thread_entry *current; |
494 | |||
495 | /* Get the entry for the current running thread. */ | ||
496 | current = cores[CURRENT_CORE].running; | ||
497 | |||
498 | /* At next task switch scheduler will immediately change the thread | ||
499 | * state (and we also force the task switch to happen). */ | ||
500 | if (timeout) | ||
501 | { | ||
502 | #ifdef THREAD_EXTRA_CHECKS | ||
503 | /* We can store only one thread to the "list" if thread is used | ||
504 | * in other list (such as core's list for sleeping tasks). */ | ||
505 | if (*list) | ||
506 | panicf("Blocking violation T->*B"); | ||
507 | #endif | ||
508 | |||
509 | current->statearg = | ||
510 | SET_STATE(STATE_BLOCKED_W_TMO, current_tick + timeout); | ||
511 | *list = current; | ||
512 | |||
513 | /* Now force a task switch and block until we have been woken up | ||
514 | * by another thread or timeout is reached. */ | ||
515 | switch_thread(true, NULL); | ||
516 | |||
517 | /* If timeout is reached, we must set list back to NULL here. */ | ||
518 | *list = NULL; | ||
519 | } | ||
520 | else | ||
521 | { | ||
522 | #ifdef THREAD_EXTRA_CHECKS | ||
523 | /* We are not allowed to mix blocking types in one queue. */ | ||
524 | if (*list && GET_STATE((*list)->statearg) == STATE_BLOCKED_W_TMO) | ||
525 | panicf("Blocking violation B->*T"); | ||
526 | #endif | ||
527 | |||
528 | current->statearg = SET_STATE(STATE_BLOCKED, 0); | ||
529 | |||
530 | /* Now force a task switch and block until we have been woken up | ||
531 | * by another thread or timeout is reached. */ | ||
532 | switch_thread(true, list); | ||
533 | } | ||
534 | |||
535 | /* Clear all flags to indicate we are up and running again. */ | ||
536 | current->statearg = 0; | ||
290 | } | 537 | } |
291 | 538 | ||
539 | void wakeup_thread(struct thread_entry **list) | ||
540 | { | ||
541 | struct thread_entry *thread; | ||
542 | |||
543 | /* Check if there is a blocked thread at all. */ | ||
544 | if (*list == NULL) | ||
545 | return ; | ||
546 | |||
547 | /* Wake up the last thread first. */ | ||
548 | thread = *list; | ||
549 | |||
550 | /* Determine thread's current state. */ | ||
551 | switch (GET_STATE(thread->statearg)) | ||
552 | { | ||
553 | case STATE_BLOCKED: | ||
554 | /* Remove thread from the list of blocked threads and add it | ||
555 | * to the scheduler's list of running processes. */ | ||
556 | remove_from_list(list, thread); | ||
557 | add_to_list(&cores[CURRENT_CORE].running, thread); | ||
558 | thread->statearg = 0; | ||
559 | break; | ||
560 | |||
561 | case STATE_BLOCKED_W_TMO: | ||
562 | /* Just remove the timeout to cause scheduler to immediately | ||
563 | * wake up the thread. */ | ||
564 | thread->statearg &= 0xC0000000; | ||
565 | *list = NULL; | ||
566 | break; | ||
567 | |||
568 | default: | ||
569 | /* Nothing to do. Thread has already been woken up | ||
570 | * or it's state is not blocked or blocked with timeout. */ | ||
571 | return ; | ||
572 | } | ||
573 | } | ||
292 | 574 | ||
293 | /*--------------------------------------------------------------------------- | 575 | /*--------------------------------------------------------------------------- |
294 | * Create thread on the current core. | 576 | * Create thread on the current core. |
295 | * Return ID if context area could be allocated, else -1. | 577 | * Return ID if context area could be allocated, else -1. |
296 | *--------------------------------------------------------------------------- | 578 | *--------------------------------------------------------------------------- |
297 | */ | 579 | */ |
298 | int create_thread(void (*function)(void), void* stack, int stack_size, | 580 | struct thread_entry* |
299 | const char *name) | 581 | create_thread(void (*function)(void), void* stack, int stack_size, |
582 | const char *name IF_PRIO(, int priority)) | ||
300 | { | 583 | { |
301 | return create_thread_on_core(CURRENT_CORE, function, stack, stack_size, | 584 | return create_thread_on_core(CURRENT_CORE, function, stack, stack_size, |
302 | name); | 585 | name IF_PRIO(, priority)); |
303 | } | 586 | } |
304 | 587 | ||
305 | /*--------------------------------------------------------------------------- | 588 | /*--------------------------------------------------------------------------- |
@@ -307,18 +590,28 @@ int create_thread(void (*function)(void), void* stack, int stack_size, | |||
307 | * Return ID if context area could be allocated, else -1. | 590 | * Return ID if context area could be allocated, else -1. |
308 | *--------------------------------------------------------------------------- | 591 | *--------------------------------------------------------------------------- |
309 | */ | 592 | */ |
310 | int create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size, | 593 | struct thread_entry* |
311 | const char *name) | 594 | create_thread_on_core(unsigned int core, void (*function)(void), |
595 | void* stack, int stack_size, | ||
596 | const char *name IF_PRIO(, int priority)) | ||
312 | { | 597 | { |
313 | unsigned int i; | 598 | unsigned int i; |
314 | unsigned int stacklen; | 599 | unsigned int stacklen; |
315 | unsigned int *stackptr; | 600 | unsigned int *stackptr; |
601 | int n; | ||
316 | struct regs *regs; | 602 | struct regs *regs; |
317 | struct thread_entry *thread; | 603 | struct thread_entry *thread; |
318 | 604 | ||
319 | if (cores[core].num_threads >= MAXTHREADS) | 605 | for (n = 0; n < MAXTHREADS; n++) |
320 | return -1; | 606 | { |
321 | 607 | if (cores[core].threads[n].name == NULL) | |
608 | break; | ||
609 | } | ||
610 | |||
611 | if (n == MAXTHREADS) | ||
612 | return NULL; | ||
613 | |||
614 | |||
322 | /* Munge the stack to make it easy to spot stack overflows */ | 615 | /* Munge the stack to make it easy to spot stack overflows */ |
323 | stacklen = stack_size / sizeof(int); | 616 | stacklen = stack_size / sizeof(int); |
324 | stackptr = stack; | 617 | stackptr = stack; |
@@ -328,10 +621,17 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack | |||
328 | } | 621 | } |
329 | 622 | ||
330 | /* Store interesting information */ | 623 | /* Store interesting information */ |
331 | thread = &cores[core].threads[cores[core].num_threads]; | 624 | thread = &cores[core].threads[n]; |
332 | thread->name = name; | 625 | thread->name = name; |
333 | thread->stack = stack; | 626 | thread->stack = stack; |
334 | thread->stack_size = stack_size; | 627 | thread->stack_size = stack_size; |
628 | thread->statearg = 0; | ||
629 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
630 | thread->priority = priority; | ||
631 | highest_priority = 100; | ||
632 | #endif | ||
633 | add_to_list(&cores[core].running, thread); | ||
634 | |||
335 | regs = &thread->context; | 635 | regs = &thread->context; |
336 | #if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM) | 636 | #if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM) |
337 | /* Align stack to an even 32 bit boundary */ | 637 | /* Align stack to an even 32 bit boundary */ |
@@ -343,8 +643,7 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack | |||
343 | #endif | 643 | #endif |
344 | regs->start = (void*)function; | 644 | regs->start = (void*)function; |
345 | 645 | ||
346 | wake_up_thread(); | 646 | return thread; |
347 | return cores[core].num_threads++; /* return the current ID, e.g for remove_thread() */ | ||
348 | } | 647 | } |
349 | 648 | ||
350 | /*--------------------------------------------------------------------------- | 649 | /*--------------------------------------------------------------------------- |
@@ -352,44 +651,58 @@ int create_thread_on_core(unsigned int core, void (*function)(void), void* stack | |||
352 | * Parameter is the ID as returned from create_thread(). | 651 | * Parameter is the ID as returned from create_thread(). |
353 | *--------------------------------------------------------------------------- | 652 | *--------------------------------------------------------------------------- |
354 | */ | 653 | */ |
355 | void remove_thread(int threadnum) | 654 | void remove_thread(struct thread_entry *thread) |
356 | { | 655 | { |
357 | remove_thread_on_core(CURRENT_CORE, threadnum); | 656 | if (thread == NULL) |
657 | thread = cores[CURRENT_CORE].running; | ||
658 | |||
659 | /* Free the entry by removing thread name. */ | ||
660 | thread->name = NULL; | ||
661 | #ifdef HAVE_PRIORITY_SCHEDULING | ||
662 | highest_priority = 100; | ||
663 | #endif | ||
664 | |||
665 | if (thread == cores[CURRENT_CORE].running) | ||
666 | { | ||
667 | remove_from_list(&cores[CURRENT_CORE].running, thread); | ||
668 | switch_thread(false, NULL); | ||
669 | return ; | ||
670 | } | ||
671 | |||
672 | if (thread == cores[CURRENT_CORE].sleeping) | ||
673 | remove_from_list(&cores[CURRENT_CORE].sleeping, thread); | ||
674 | |||
675 | remove_from_list(NULL, thread); | ||
358 | } | 676 | } |
359 | 677 | ||
360 | /*--------------------------------------------------------------------------- | 678 | #ifdef HAVE_PRIORITY_SCHEDULING |
361 | * Remove a thread on the specified core from the scheduler. | 679 | void thread_set_priority(struct thread_entry *thread, int priority) |
362 | * Parameters are the core and the ID as returned from create_thread(). | ||
363 | *--------------------------------------------------------------------------- | ||
364 | */ | ||
365 | void remove_thread_on_core(unsigned int core, int threadnum) | ||
366 | { | 680 | { |
367 | int i; | 681 | if (thread == NULL) |
368 | 682 | thread = cores[CURRENT_CORE].running; | |
369 | if (threadnum >= cores[core].num_threads) | 683 | |
370 | return; | 684 | thread->priority = priority; |
371 | 685 | highest_priority = 100; | |
372 | cores[core].num_threads--; | ||
373 | for (i=threadnum; i<cores[core].num_threads-1; i++) | ||
374 | { /* move all entries which are behind */ | ||
375 | cores[core].threads[i] = cores[core].threads[i+1]; | ||
376 | } | ||
377 | |||
378 | if (cores[core].current_thread == threadnum) /* deleting the current one? */ | ||
379 | cores[core].current_thread = cores[core].num_threads; /* set beyond last, avoid store harm */ | ||
380 | else if (cores[core].current_thread > threadnum) /* within the moved positions? */ | ||
381 | cores[core].current_thread--; /* adjust it, point to same context again */ | ||
382 | } | 686 | } |
687 | #endif | ||
383 | 688 | ||
384 | void init_threads(void) | 689 | void init_threads(void) |
385 | { | 690 | { |
386 | unsigned int core = CURRENT_CORE; | 691 | unsigned int core = CURRENT_CORE; |
387 | 692 | ||
388 | cores[core].num_threads = 1; /* We have 1 thread to begin with */ | 693 | memset(cores, 0, sizeof cores); |
389 | cores[core].current_thread = 0; /* The current thread is number 0 */ | 694 | cores[core].sleeping = NULL; |
695 | cores[core].running = NULL; | ||
390 | cores[core].threads[0].name = main_thread_name; | 696 | cores[core].threads[0].name = main_thread_name; |
391 | /* In multiple core setups, each core has a different stack. There is probably | 697 | cores[core].threads[0].statearg = 0; |
392 | a much better way to do this. */ | 698 | #ifdef HAVE_PRIORITY_SCHEDULING |
699 | cores[core].threads[0].priority = PRIORITY_USER_INTERFACE; | ||
700 | highest_priority = 100; | ||
701 | #endif | ||
702 | add_to_list(&cores[core].running, &cores[core].threads[0]); | ||
703 | |||
704 | /* In multiple core setups, each core has a different stack. There is probably | ||
705 | a much better way to do this. */ | ||
393 | if (core == CPU) | 706 | if (core == CPU) |
394 | { | 707 | { |
395 | cores[CPU].threads[0].stack = stackbegin; | 708 | cores[CPU].threads[0].stack = stackbegin; |
@@ -405,28 +718,24 @@ void init_threads(void) | |||
405 | #else | 718 | #else |
406 | cores[core].threads[0].context.start = 0; /* thread 0 already running */ | 719 | cores[core].threads[0].context.start = 0; /* thread 0 already running */ |
407 | #endif | 720 | #endif |
408 | cores[core].num_sleepers = 0; | ||
409 | } | ||
410 | |||
411 | int thread_stack_usage(int threadnum) | ||
412 | { | ||
413 | return thread_stack_usage_on_core(CURRENT_CORE, threadnum); | ||
414 | } | 721 | } |
415 | 722 | ||
416 | int thread_stack_usage_on_core(unsigned int core, int threadnum) | 723 | int thread_stack_usage(const struct thread_entry *thread) |
417 | { | 724 | { |
418 | unsigned int i; | 725 | unsigned int i; |
419 | unsigned int *stackptr = cores[core].threads[threadnum].stack; | 726 | unsigned int *stackptr = thread->stack; |
420 | |||
421 | if (threadnum >= cores[core].num_threads) | ||
422 | return -1; | ||
423 | 727 | ||
424 | for (i = 0;i < cores[core].threads[threadnum].stack_size/sizeof(int);i++) | 728 | for (i = 0;i < thread->stack_size/sizeof(int);i++) |
425 | { | 729 | { |
426 | if (stackptr[i] != DEADBEEF) | 730 | if (stackptr[i] != DEADBEEF) |
427 | break; | 731 | break; |
428 | } | 732 | } |
429 | 733 | ||
430 | return ((cores[core].threads[threadnum].stack_size - i * sizeof(int)) * 100) / | 734 | return ((thread->stack_size - i * sizeof(int)) * 100) / |
431 | cores[core].threads[threadnum].stack_size; | 735 | thread->stack_size; |
736 | } | ||
737 | |||
738 | int thread_get_status(const struct thread_entry *thread) | ||
739 | { | ||
740 | return GET_STATE(thread->statearg); | ||
432 | } | 741 | } |
diff --git a/firmware/usb.c b/firmware/usb.c index 6be5fda093..0be6c4011e 100644 --- a/firmware/usb.c +++ b/firmware/usb.c | |||
@@ -558,8 +558,9 @@ void usb_init(void) | |||
558 | last_usb_status = false; | 558 | last_usb_status = false; |
559 | 559 | ||
560 | #ifndef BOOTLOADER | 560 | #ifndef BOOTLOADER |
561 | queue_init(&usb_queue); | 561 | queue_init(&usb_queue, true); |
562 | create_thread(usb_thread, usb_stack, sizeof(usb_stack), usb_thread_name); | 562 | create_thread(usb_thread, usb_stack, sizeof(usb_stack), |
563 | usb_thread_name IF_PRIO(, PRIORITY_SYSTEM)); | ||
563 | 564 | ||
564 | tick_add_task(usb_tick); | 565 | tick_add_task(usb_tick); |
565 | #endif | 566 | #endif |
diff --git a/uisimulator/sdl/kernel.c b/uisimulator/sdl/kernel.c index b9ffe0eefe..bfe6062450 100644 --- a/uisimulator/sdl/kernel.c +++ b/uisimulator/sdl/kernel.c | |||
@@ -32,8 +32,10 @@ int set_irq_level (int level) | |||
32 | return (_lv = level); | 32 | return (_lv = level); |
33 | } | 33 | } |
34 | 34 | ||
35 | void queue_init(struct event_queue *q) | 35 | void queue_init(struct event_queue *q, bool register_queue) |
36 | { | 36 | { |
37 | (void)register_queue; | ||
38 | |||
37 | q->read = 0; | 39 | q->read = 0; |
38 | q->write = 0; | 40 | q->write = 0; |
39 | } | 41 | } |
@@ -47,7 +49,7 @@ void queue_wait(struct event_queue *q, struct event *ev) | |||
47 | { | 49 | { |
48 | while(q->read == q->write) | 50 | while(q->read == q->write) |
49 | { | 51 | { |
50 | switch_thread(); | 52 | switch_thread(true, NULL); |
51 | } | 53 | } |
52 | 54 | ||
53 | *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; | 55 | *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK]; |
@@ -97,8 +99,11 @@ void queue_clear(struct event_queue* q) | |||
97 | q->write = 0; | 99 | q->write = 0; |
98 | } | 100 | } |
99 | 101 | ||
100 | void switch_thread (void) | 102 | void switch_thread(bool save_context, struct thread_entry **blocked_list) |
101 | { | 103 | { |
104 | (void)save_context; | ||
105 | (void)blocked_list; | ||
106 | |||
102 | yield (); | 107 | yield (); |
103 | } | 108 | } |
104 | 109 | ||
@@ -160,7 +165,7 @@ void mutex_init(struct mutex *m) | |||
160 | void mutex_lock(struct mutex *m) | 165 | void mutex_lock(struct mutex *m) |
161 | { | 166 | { |
162 | while(m->locked) | 167 | while(m->locked) |
163 | switch_thread(); | 168 | switch_thread(true, NULL); |
164 | m->locked = true; | 169 | m->locked = true; |
165 | } | 170 | } |
166 | 171 | ||